C语言以C关键字、表达式、语句,以及这些元素的使用规则为基础。ANSI C标准不仅描述了C语言,还描述了C预处理器的工作机制。在编译之前,先由预处理器检查程序,根据程序中使用的预处理器指令,使用符号缩略语所代表的内容替换程序中的缩略语。

预处理之前的翻译

在程序预处理之前,编译器会先做几次翻译处理。编译器先把源代码中出现的字符映射到源字符集。该过程处理多字节字符和使C外观更加国际化的三元字符的扩展。(这是因为有的键盘不能提供C使用的所有符号,所以C是哟娜个一组三字符序列为一些符号提供可选的表示方法,比如使用 ??= 表示 #,C99提供了一种二元字符来代替三元字符)。C源码中出现这类三元字符时要先进行替换。

阅读全文 »

这个问题其实比较常见了,但是经常会出错,就是C中函数的参数是值传递的,即使对于指针,也是值传递。很多高级语言在这一点是相通的。

今天看到这个问题是在 c-fqa.com 上的一个问题,看下面的代码:

void f(int *ip) {
static int dummy = 5; // static make dummy accessiable for whole file
ip = &dummy;
}

int *ip;
f(ip);

这时候ip指向哪里呢?实际上ip可能指向任何地址。因为ip没有初始化,传递给f函数调用的参数只是指针值的拷贝,对拷贝的修改并不会改变 ip 本身的内容。要达到本来的目的,需要传入 ip的地址,也就是指针的指针作为参数:

void f(int **ipp) {
static int dummy = 5; // if no static here, then ip can be anywhere, *ip can be any value
*ip = &dummy;
}

int *ip;
f(&ip);

另一种方法是把结果的指针作为函数的返回值,这是更常用的方式:

int *f() {
static int dummy = 5;
return &dummy;
}
int *ip = f();

另一个例子是,定制一个 malloc 的自己的版本:

void mymalloc(void *retp, size_t size) {
retp = malloc(size);
if (retp == NULL) {
fprintf(stderr, "out of memory\n");
exit(EXIT_FAILURE);
}
}

看起来没有什么问题,但是在调用这个函数时并不能正常工作,因为被调用函数接受的指针是调用者传入的指针的拷贝。

C always uses pass by value. You can simulate pass by reference yourself, by defining functions which accept pointers and then using the & operator when calling, and the compiler will essentially simulate it for you when you pass an array to a function

这些内容在Java和Go中也是通用的,指针作为参数实际上也是值传递的哦。

参考:

在之前的认识里面,malloc 函数分配一定大小的存储空间,返回一个 void * 类型的指针,一直都是要对返回类型做显示的类型转换,但是今天在 stackoverflow 上面看到一个提问,提到这个强制的类型转换是不建议使用的。这是为什么呢?

一般我们这样使用 malloc :

int *sieve = (int *)malloc(sizeof(int) * length);

我们知道malloc返回的是一个 void *,即指向任何类型的指针,在这种情况下,返回的指针能自动地安全地提升到任何其他类型的指针类型,这可以是一个隐式的类型转换。

加上显式的类型转换后,代码显得更加混乱,尤其是当指针类型很复杂的时候,显示的类型转换就不是那么好理解,并且容易出错。

在没有 #inlcude <stdlib.h> 就使用malloc时,编译器会认为malloc的返回值是 int 类型,如果不使用显式的类型转换,编译器会抛出一个隐式类型转换警告,而如果使用了显式类型转换则不会抛出这个警告(而导致潜在的错误)。

Suppose that you call malloc but forget to #include <stdlib.h>. The compiler is likely to assume that malloc is a function returning int, which is of course incorrect, and will lead to trouble.

事实上,很多人认为,虽然显式的类型转换也可以正常工作,但是这并不代表这么做是正确的。包含显式的转换是一种错误的做法,因为会存在一些潜在的风险,上面的代码是一种很不好的风格,首先是不需要的显示类型转换,其次是重复了不需要的类型信息 int,更好的做法是直接使用变量的间接引用(dereference)作为类型信息,推荐的使用方式如下:

int *sieve = malloc(length * sizeof *sieve);

sizeof 后面的括号只有当操作数是类型时才是必须的,后面是变量时,大括号不是必须的,因为sizeof是一个操作符,而不是一个函数

然而,只是C不推荐使用强制的类型转换,而C++仍然需要显示转换,这真是忧伤。不过在C++中应该使用 new 而不是malloc,并且不应该使用C++编译器来编译C程序。并且C/C++本来就不是完全兼容的,并不推荐用一份代码去满足两份标准。

其实说这么多,malloc的显式类型转换到底写不写还是个人习惯,只是应该知道,可以不写,并且应该不写,推荐不要使用显式类型转换了。

GUN C:

You can store the result of malloc into any pointer variable without a cast, because ISO C automatically converts the type void * to another type of pointer when necessary. But the cast is necessary in contexts other than assignment operators or if you might want your code to run in traditional C.

ISO C11:

The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated)

参考:

联合(union)

联合是一个能在同一存储空间里(但是不是同时)存储不同类型数据的数据类型。用来存储某种即没有规律,事先未知顺序的混合数据类型。联合使用于结构同样的方式建立,也需要一个联合模板和联合变量,下面是一个例子:

union hold {
int digit;
double bigfl;
char letter;
};

union hold fit;

一个hold结构可以含有一个int型数值或者一个double型数值或者一个char型数值。一个联合的变量可以存储模板中声明的成员的某一个。编译器分配空间时,会分析各成员需要的空间,然后按最大需求分配。因为联合一个时刻只存储一个值,所以初始化与结构并不一样。

fit.letter = 'A';
fit.digit = 127;
union hold holdA = { .bigfl = 10.08 };

要注意的是,需要程序员维护存储在联合变量的是哪一个成员,有时候使用了一个成员保存值,而使用另一个成员来查看这些内容,这有时很有用,但需要是程序员管理下进行的,否则会导致错误。

枚举(enumerated type)

枚举类型声明代表整数常量的符号名称,通过使用关键字 enum 可以创建一个新的类型,并可以指定它可以具有的值,实际上enum常量是int类型的,因此在任何使用int类型的地方都可以使用它。枚举使得程序有更高的可读性,它的语法与结构很相似。

enum spectrum { red, orange, yellow, blue };
enum spectrum color;

// 可以当作int使用
for (color = red; color <= blue; color++)
...

类型声明中的 red, orange 等我们称之为 枚举常量,规定枚举常量都是int类型的,而定义的变量 color 称为枚举变量,可以较为宽松地限定为任意一种整数类型,常有编译器决定,比如我们这里color的范围在0-3之间,可以选择为unsigned char表示。要注意对枚举变量的一元操作符在C++中是不允许的,如果代码可能迁移到C++则不应该这样用。

枚举常量默认从0开始递增,也可以为枚举列表中的常量指定特定的值。如:

enum level { low = 100, medium = 101, high };

这样后面没有指定值的常量会赋予后续的值(即high为102)。Go中有更加强大的 itoa 生成更加复杂的赋值模式。

可以字啊同一个作用域内对一个变量和一个标记使用同一个名字而不会发生错误,但是不能在同一作用域内使用名字相同的两个标记或者变量。

typedef

typedef 是一种高级数据特性,它能够为某一类型创建自己的名字,与#define有3个不同之处

  • typedef 给出的符号名称仅限于对类型,而不是对值
  • typedef 的解释有编译器执行,而不是预处理器(也就是说 #define 由预处理器执行
  • 虽然typedesf的范围有限,但在受限范围内,typedef比 #define更灵活

下面是一个使用示例:

typedef unsigned int BYTE;
BYTE x, y[2], *z

typedef 的作用域取决于typedef语句所在的位置,它的作用域与变量相似。通常typedef定义的类型使用大写字母,以提醒用户这个类型名称实际上以一个符号缩写(当然也可以使用小写字母)。

实际上,在 <sys/types.h> 中定义的很多很多类型,比如 time_t, size_t 都是使用typedef定义的整数类型。这是由于C标准留给具体实现来决定使用哪种类型。

注意typedef和#define的区别:

typedef char * STRING
STRING name, sign; // char *name, *sign;

// define
#define STRING char *
STRING name, sign; // char *name, sign;

一种更常用的 typedef 场景是对strut 结构体创建新的类型:

typedef struct book {
char title[20];
float price;
} Book;
Book cspp;

这样使用更见方便,也更见常见。

一些奇特的声明

这里记录几个比较有用的:

int *reisks[10];		// 表示具有10个元素的数组,每个元素是一个指向int的指针
int (*risks)[10]; // 一个指针,指向具有10个元素的int数组
int *oof[3][4]; // 一个 3×4的数组,每个元素是一个指向int的指针
int (* uuf)[3][4]; // 一个指针,指向 3×4的int数组
int (* uof[3])[4]; // 一个具有3个元素的数组,每个元素是一个指向具有4个元素的int数组的指针

理解这部分,需要知道, [] 和 () 具有相同的优先级,其优先级比 * 高,且 [] 和 () 都是从左到右进行结合的。这一块确实是比较难以理解的,过一段时间又会混乱掉。

再看一下复杂的函数返回值类型:

char * fump();			// 返回指向char的指针**的函数**
char (* frump)(); // 指向返回类型为char的**函数的指针**
char (* flump[3])(); // 由3个指针组成**的数组**,每个指针指向返回类型为char**的函数**

一个技巧是,首先确定类型,是数组、指针还是函数,在确认其他的。

更复杂的typedef应用:

typedef int arr5[5];		// arr5 是一个有5个元素的int数组类型
typedef arr5 * p_arr5; // p_arr5是指向具有5个元素的int数组的指针 的类型
typedef p_arr5 arrp10[10]; // 一个具有10个元素的数组类型,每个元素是一个指向有5个元素的int数组

函数和指针

上面一节中,函数指针是比较难懂的,之前也确实没有用过C中的函数指针,在Go,JS甚至PHP中都用过相似的概念,这里学习一下C中的函数指针。

对于一个函数的指针,必须声明它指向的函数的类型,在C中函数的类型包括返回类型及函数的参数类型。考虑下面的函数声明:

void ToUpper(char *);

描述这个函数声明就是:一个具有char * 类型的参量,返回类型是void的函数,那么要声明这种函数的指针,可以如下:

void (*pf)(char *)

pf 就是一个指向 ToUpper类型函数的指针了。其前一个括号是结合符,后一个括号是表示这是一个函数指针,并且用于说明其参数类型。这是可以用 *pf 代替函数名 ToUpper。 第一个括号是不可省略的,之前的文章里已经提到过,void *pf(char *)表示一个返回一个指针的函数。

有了函数指针后,可以把适当类型的函数的标识(地址)赋值给它,函数名即是函数的地址:

char mis[12] = "how are you";
pf = ToUpper; // 不需要 ToUpper()
(*pf)(mis);

pf(mis);

像上面的两种使用方式在ANSI C中都可以,第一种是C和Unix开发者使用的,第二种是Berkeley的Unix扩展这采用的,而K &R C不允许使用第二种形式,ANSI C保持了对两种方式的兼容。一个使用函数指针的示例:

void ToUpper(char *str) {
while (*str != 0) {
if (*str >= 'a' && *str <= 'z')
*str -= 32;
str++;
}
}

void ToLower(char *str) {
while (*str != 0) {
if (*str >= 'A' && *str <= 'Z')
*str += 32;
str++;
}
}

void show(void (*fp)(char *),char *str) {
fp(str);
printf("str after fp: %s\n", str);
}

int main() {
char *hi = "how are you?";
void (*fp)(char *);
fp = ToUpper; // 类型相同的函数才能赋值给该指针
show(fp, hi); // 函数指针作为参数
fp = ToLower;
show(fp, hi);
return 0;
}

可以使用typedef简化函数指针的声明,比如使用:

typedef void(*V_FP_CHARP) (char *);
void show(V_FP_CHARP, char *);

V_FP_CHARP pfun;

这样的typedef用法和之前简单的 typedef unsigned char BYTE 形式不太一样,不过结合前面对函数指针的介绍,应该也可以理解了。

完。

参考:

  • 除了 C Primer Plus,然而并没有

结构体一块本科的时候就没有学好,在学习Go的时候学习了Go定义结构体的方式,最近看C Primer Plus的结构体一章,发现Go借鉴了很多C中结构体的东西,并且这本书中讲的结构体和本科书上的结构体部分很不一样,讲的更加容易理解。

这里只记一些最重要的,因为对结构体已经有一定的基础了,虽然很久没有使用过了。

结构体的声明和变量定义

声明结构体的关键字是 struct ,结构体的声明是描述结构如何组合的主要方法。下面是一个示例:

struct book {
title char[20];
char author[20];
price float;
}

// 定义一个结构体的变量
struct book cpp;

我们把struct 后面的 book 称作(可选的)标记,用来引用该结构的快速标记。

阅读全文 »


CentOS 7正式废弃了很多旧的工具包,比如历史悠久的ifconfig, netstat等网络相关的命令,还有locate这些命令也没有了。新的系统使用ip, ss, net等命令替代了之前的网络操作命令。

新的命令设计的比较复杂,其帮助文档看起来都头晕,这里记录一下一下常见的操作。

ip 命令

没有了ifconfig命令之后,ip命令是其替代品。ip命令的作用如下:

ip - show / manipulate routing, devices, policy routing and tunnels

命令使用格式如下:

ip [ OPTIONS ] OBJECT { COMMAND | help }
ip [ -force ] -batch filename
OBJECT := { link | addr | addrlabel | route | rule | neigh | ntable | tunnel | tuntap |
maddr | mroute | mrule | monitor | xfrm | netns | l2tp | tcp_metrics }
OPTIONS := { -V[ersion] | -s[tatistics] | -r[esolve] | -f[amily] { inet | inet6 | ipx |
dnet | link } | -o[neline] }

可以看到二级命令非常多,很难记。最常用的是 ip addr 也可以简写为 ip a(ip命令中更有很多这种简写方法)。操作网络地址相关内容,比如列出ip地址,添加ip地址,删除ip等待。

ip addr show
# Only show TCP/IP IPv4
ip -4 a
# Only show TCP/IP IPv4
ip -6 a

# show eth0 interface
ip a show eth0

# show on running interface
ip link ls up

# add/del ip address
ip a add {ip_addr/mask} dev {intereface} [label label_name] // 可选的设置一个label
ip addr add 192.168.0.123/24 dev eth0

#remove ip address
ip a del {ip_addr} dev {interface}
ip addr del 192.168.0.123 dev eth0

# flush ip address; delete all the IP addresses matches
# 可以flush一个地址或者一个label标记的所有地址
ip a flush label "label"
ip -s a f to 192.168.2.0/24 // -s 输出统计信息 to limit to given IP address/prefix

# up or down a device
ip link set dev {interface} {up|down}
ip l set dev eth0 down

ip link set 命令可以设置很多的值,看一下自动补全提示:

$ ip l set <tab>
address -- specify unicast link layer (MAC) ad
arp -- change ARP flag on device
brd -- specify broadcast link layer (MAC)
broadcast -- specify broadcast link layer (MAC)
dev -- specify device
down -- change state do down
dynamic -- change DYNAMIC flag on device
mtu -- specify maximum transmit unit
multicast -- change MULTICAST flag on device
name -- change name of device
peer -- specify peer link layer (MAC) addre
promisc -- set promiscious mode
txqlen -- specify length of transmit queue
txqueuelen -- specify length of transmit queue
up -- change state to up

一般用法都是 ip link set {cmd} dev {interface}。比如设置mtu:

ip link set mtu 3000 dev eth0

ip命令还能查看与邻近节点(neighbour)的可达性:

ip n show         // same as ip neigh show
ip n add {ip_addr} lladdr {MAC/LLADDRESS} dev {interface} nud {perm|noarp|stale|reachable}
ip n del {ip_addr} dev eth0

会输出附近节点的arp信息。可以手动添加这些arp条目。

路由表信息也由ip命令提供,使用route/r 子命令操作:

# list route table
ip r
ip r list 192.168.0.0/24
ip r add {default} {network/mask} dev {interface}
ip r add (default) {network/mask} via {gateway_ip}
ip r del default
ip r del network/mask dev wth0

ip命令远比上面介绍的部分复杂,这里不能一一列出了,使用一个带tab补全的终端非常有用,另外虽然ifconfig命令没有了,但是基于图形用户界面的 nmtui (network management text user interface) 还是预装了,可以用它来配置ip/DNS等。如果没有安装,使用下面的命令安装: sudo yum install NetworkManager-tui -y

ss 命令

ss是另一个很重要的工具,ss是socket statistics的缩写,用于代替之前使用netstat命令。ss能够显示比netstat更多的信息并且速度也更快。netstat是从 /proc 下的文件中读取信息再整理显示的,而 ss 命令直接从内核空间获取信息。

ss的man页面介绍如下:

ss - another utility to investigate sockets

直接执行 ss 会列出当前所有已建立的非监听的(non-listening)连接,一个常用的参数 -ntl,参数意义为:

  • -n –numeric,显示端口数字而不是服务名字,比如显示 80 而不是 http
  • -t –tcp, 即显示 tcp 套接字,同理常用 -u 表示 udo 套接字
  • -l –listening,也好理解,默认不显示监听的套接字,这个参数指明只显示监听中的套接字
  • -4 –ipv4也是常用的,在查看服务监听状态时,常指定 -4 或者 -6 结果更加清晰
  • -p –processes,显示使用这个套接字的进程id,这个参数需要 sudo 权限
  • -s –summary,显示套接字使用的统计信息
  • -o –options,显示相关的时间信息

还可以更具套接字状态过滤输出,比如下面的命令:

ss -t4 state established
ss -t4 state time-wait

连接的状态有很多中,常用如下:

  1. established
  2. syn-sent
  3. syn-recv
  4. time-wait
  5. closed
  6. closing
  7. all
  8. connected

还可以通过指定dport和sport过滤输出:

# 还可以使用 or,666
ss -nt dst :443 or dst :80
// dport 大于1024的连接
ss -nt dst gt :1024

当然更常用的过滤是 grep 啦,哈哈哈。

要监控网络流量的动态,可以用top相关命令,也可以用watch工具:

watch -n 1 "ss -t4"

这样每秒中会刷新一次ss的结果。

参考:

PHP 7正式版终于在今天发布了,虽然在官网 php.net 还没有挂出链接(原来是因为中国时区比较早,现在已经有下载了),但是在鸟哥的微信公众号中给出来下载地址,在github上也有了 7.0.0 的release。不知道为什么github上面的状态一直显示 build error。但是下载源文件编译是成功的。基本的安装步骤和之前编译安装 beta1 是一样的。

官方的下载地址: http://www.php.net/downloads.php

可以参考之前的文章: http://wuxu92.github.io/compile-and-install-php7-beta1/ 唯一的区别是正式版没有了 --with-MySQL 选项,因为正式版已经没有旧的mysql函数的支持了,需要使用 mysqli 或者 PDO 替代早已不建议使用的mysql函数。

下载链接: http://cn2.php.net/get/php-7.0.0.tar.gz/from/this/mirror

阅读全文 »

输入输出(I/O)是在主存和外部设备(磁盘,终端,网络等)之间拷贝数据的过程。所有语言的运行时系统都系统高级大带缓冲区的IO函数,在高级IO函数工作良好的时候,没有必要使用系统级IO。

Unix I/O

可以把Uninx文件看作就是一个m个字节的序列,所有的IO设备。如网络,磁盘,终端都被模型化为文件,而所有的输入输出都被当作对应文件的读写来执行。这种将设备优雅地映射为文件的方式,允许Unix内核引出一个简单、低级的应用接口,称为 Unix IO。

  • 打开文件。一个应用程序要求内核打开相应的文件来访问一个IO设备,内核会返回一个小的非负整数,称为文件描述符(fd),在对此文件的操作依赖于这个整数型的描述符。内核记录文件打开的文件的所有信息,而程序只记住这个描述符即可。

    Unix shell为每个进程在开始时就打开三个文件:标准输入(0),标准输出(1),标准错误(2)(所以可以理解Linux系统中输出重定向的1,2的意义了)。头文件 unistd.h 定义了常量 STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO来代替现实的描述符值。

  • 改变当前的文件位置。对于打开的文件,内核保持一个文件位置k,相当于offset,初始为0。代表文件位置是从文件开头起始的字节偏移量,应用程序可以通过 seek 操作设置当前文件的 k。
  • 读写文件。读写文件就是从文件拷贝数据到存储器,或者从存储器拷贝数据到文件。
  • 关闭文件。应用完成了对文件的访问之后,它就通知内核关闭这个文件。内核释放打开这个文件时创建的数据结构,并将这个描述符恢复到可用的描述符池中。无论一个进程因为何种原因终止,内核都会关闭所有打开的文件,并释放它们的存储器资源。
    阅读全文 »

在C语言程序中,与存储器有关的错误属于那些最令人惊恐的错误之一,因为它们在时间上和空间上经常是在距离错误一段距离之后才表现出来。将错误的数据写到错误的位置,你的程序可能在最终失败之前运行了好几个小时,且程序终止的位置离导致错误的位置已经很远了。

间接引用坏指针

再进程的虚拟地址空间中有较大的区域没有映射到任何有意义的数据,如果我们试图间接引用一个指向这些区域的指针,那么操作系统就会以段异常中止程序。而且虚拟存储器的某些区域是只读的,试图写这些区域会以保护异常中止这个程序。

间接引用换指针一个常见的(初学者常犯的)的示例就是 scanf 错误,写成如 scanf("%d", val);这种情况下,scanf把val的内容解释为一个地址,并试图将一个字写入到这个位置,在最好的情况下,程序以异常中止,如果val正好指向虚拟存储器的某个合法读/写区域,就会覆盖该区域而导致灾难性的后果。(我们知道块内局部变量并不会自动初始化,所以局部变量val可能指向任何值)。

阅读全文 »

P130. 着手计划经济生活的民主主义的政治家很快会面临这样的选择:是僭取独裁权力,还是放弃他的计划,而极权主义的独裁者不久必定会在置一般的道德于不顾和遭受失败之间做出选择。正是这个缘故,那些无耻之徒和放荡不羁之人,才在一个趋向极权主义的社会里有更多的获得成功的希望。

P131. 道德和制度之间的相互作用很可能产生的结果是,集体主义所产生的道德和导致人们要求集体主义的道德理想,将是截然不同的。可以这样认为,即让要求集体主义制度的愿望是来自高度的道德动机,那种制度就一定会是最高道德的源泉。然而事实上却没有理由可以说明为什么任何一种制度都准能促进那些服务于这个制度原定目标的各种观点。(这是什么和什么)

P131. 壮大集权主义政党队伍的正是那些其思想模糊,不健全并容易动摇的人以及那些情感与情绪容易冲动的人。

人们赞同一个消极的纲领,即对敌人的憎恨,对富人的嫉妒,比赞同一个积极的纲领要容易些,这看来几乎是人性的一个法则。若要用一个信条将某个集团牢牢地团结在一起以便共同行动的话,那么将“我们”和“他们”对立起来,即向一个集团以外的人进行共同的斗争,则似乎是这个信条中的重要组成部分。

社会主义只有停留在理论的层面上时,它才是国际主义的,但是一经付诸实施,无论是在德国还是在俄国,它就满上会变成强烈的民族主义。这从一个方面说明西方世界大部分人所想象的“自由社会主义”何以是纯理论的,而各处实行的社会主义为什么却是极权主义的。集体主义不能容纳自由主义那博大的人道主义,而只能容纳极权主义的狭隘的门户之见。

如果社会或国家比个人更重要,如果它们自己的目标独立于个人的目标并超越于个人目标的话,那么,只有那些为社会所具有的共同目标而努力的个人才能被视为该社会的成员。这种见解的必然结果就是:一个人只因为他是那个集团的成员才会受到尊敬,并且只有他为公认的共同目标而工作才收到尊敬,并且他只是从他作为该集团成员的资格中获得他的全部尊严。单纯依靠他作为人的资格却不会带给他什么尊严

集体主义的门户之见和唯我独尊的倾向。其中一个最重要的因素是个人认同于一个集团的愿望,这常常是一种自卑感所引起的,因而,只有那个集团的成员资格能够使他比这个集团之外的人有优越性,他的需求才会满足。

在现代人中,有一种趋势正在增长,即把自己设想是道德的,因为他们把自己的不道德转嫁给越来越大的集团。

“大多数‘计划者’都是好战的民族主义者”。

社会主义者的民族主义和帝国主义倾向,远比一般人所认识到的更为普遍,….,他们对计划的人情特别是和崇拜强大的政治单位而鄙视小国的观点结合在一起的。”他们的社会主义(韦伯派社会主义)从骨子里是反自由主义的“。

集体主义者也为了达到他们的目的,必须建立起前所未有的巨大权力–人支配人的那种权力–并且他们的成功也取决于他们获得这种权力的程度。

坚定彻底的集体主义者绝不许做的事情简直是没有,如果它有助于”整体利益“的话,因为这个整体利益是他判定应当做什么的唯一标准。

哪里存在着一个凌驾一切的共同目标,哪里就没有任何一般的道德或规则的容身之地。(注:比如计划生育?)。。。他们要做的一些工作,其恶劣性是没有人会怀疑的,但是为了某种更崇高的目的,这些工作是必须要做的,并且还必须做得同任何其他工作一样熟练,一样有效率。