与EOF比较.当这段存在错误的代码在使用有符号字符集的机器上运行时,如果读取了一个值为\377的字节时,循环将会终止,国为这个值截短再提升之后与EOF相等.当这段代码在使用无符号的字符集的机器上运行是,这个循环将永远不会终止!
复合赋值操作符
a += expression;
它的功能相当于下面的表达式:
a = a + (expression);
唯一的不同之处是+=操作符的左操作数(此例为a)只求值一次.注意括号:它们确保表达式在执行加运算之前已被完整求值,即使它内部包含有优先级低于加法运算操作符.
下面两条语句,如果函数f没有副作用,那么它们是等价的:
a[2 * (y – 6*f(x) )] = a[2 * (y – 6*f(x) )] + 1;
a[2 * (y – 6*f(x) )] += 1;
在第一种形式中,用于选择增值位置的表达式必须书写两次,一次在赋值号的左边,另一次在赋值号的右边.由于编译器无从知道函数f是否具有副作用,所以它必须两次计算下标表达式的值.第二种形式效率更高,因为下标只计算一次.
sizeof操作符
sizeof不是函数而是一个操作符,可以按如下使用:
sizeof(int); sizeof x; //后面可以有括号,也可以没有.
Sizeof(a = b + 1);这里是求表达式的长度,但并没有对表达式进行求值,所以这里并没有对a进行赋值.
++\--操作符:
以++为例,前缀形式的++操作符出现在操作数的前面:操作数的值被增加,而表达式的值就是操作数增加后的值. 后缀形式的++操作符出现在操作数的后面:操作数的值仍被增加,但表达式的值是操作数增加前的值.
int a, b, c, d;
a = b = 10; // a和b得到值10
c = ++a; //a增加至11,c得到的值为11
d = b++; //b增加至11, d得到的值为10
上面的注释描述了这些操作符的结果,但并不说明这些结果是如何获得的.抽像的说,前缀和后缀形式的增值操作符都复制一份变量的拷贝.用于周围表达式的值正是这份拷贝(在上面的例子中,”周围表达式”是指赋值操作). 前缀操作符在进行复制之前增加变量的值,后缀操作符在进行复制之后才增加变理的值.这些操作符的结果不是被它们所修改的变量,而是变量值的一份拷贝,认识这一点非常重要.它之所以重要是因为它解释了你为什么不能像下面这样使用这些操作符:
++a = 10;
++a这个表达式的结果是a值的一份拷贝,并不是变量本身,你无法对一个值进行赋值.
优先级和求值顺序
两个相邻操作符的执行顺序邮它们的优先级决定,如果它们的优先级相同,它们的执行顺序邮它们的结合性决定.除此之外,编译器可以自由决定使用任何顺序表达式进行求值,只要它不违背逗号,&&,||和 :操作符所施加的限制.
换句话说,表达式中操作符的优先级只决定表达式的各个组成部分在求值过程中如何进行聚组.这里有一个例子:
a + b*c
在这个表达式中,乘法和加法操作符是两个相邻的操作符.由于*操作符的优先级比+操作符高,所以乘法运算先于加法运算执行.编译器在这里别无选择,它必须先执行乘法运算.
下面是一个更有趣的表达式:
a*b + c*d + e*f
如果仅由优先级决定这个表达式的求值顺序,那么所有3个乘法运算将在所有加法运算之前进行.事实上,这个顺序并不是必需的.实际上,只要保证每个乘法运算在它相邻的加法运算之前执行即可.例如,这个表达式可以会以下面的顺序进行,其中粗体的操作符表示在每个步骤中进行操作的操作符:
a * b //乘号
c * d //乘号
(a*b) + (c*d) //加号
e * f //乘号
(a*b) + (c*d) + (e*f) //第二个加号
注意第一个加法运算在最后一个乘法运算之前执行.如果这个表达式按以下的顺序执行,其结果是一样的:
a * b //乘号
c * d //乘号
e * f //乘号
(a*b) + (c*d) //加号
(a*b) + (c*d) + (e*f) //第二个加号
加法运算的结合性要求两个加法运算按照先左后右的顺序执行,但它对表达式剩余的部分的执行顺序号并未加以限制.尤其是,这里并没有任何规则要求所有的乘法运算首先执行,也没有规则规定这几个乘法运算之间谁先执行.优先级规则在这里起不到作用,优先级只对相邻操作符的执行顺序起作用.
由于表达式的求值顺序并非完全由操作符的优先级决定,所以像下面这样的语句是很危险的:
c + --c
操作符的优先级规则要求自减运算在加法运算这前进行,但我们并没有办法得知加法操作符的左操作数是在右操作数之前还是在这后进行求值,它在这个表达式中将存在区别,因数自减操作符具有副作用.—c在c之前或这后执行,表达式的结果在两种情况下将会不同.
标准说明类似这种表达式的值是未定义的.尽管每种编译器都会为这个表达式产生某个值,但到底哪个是正确的并无标准答案.因此,像这样的表达式是不可移植的,应予以避免.
下面这个表达式:
f() + g() + h()
尽管左边那个加未能运算必须在右边那个加法运算之前执行,但对于各个函数调用的顺序,并没有规则加以限制.如果它们的执行具有副作用,比如执行一些I/O任务或修改全剧变量,那么函数调用顺序的不同可能会产生不同的结果.因此,如果顺序会导致结果产生区别,你最好使用临时变量,让每个函数调用都在单独的语句中执行:
temp = f();
temp += g();
temp += h();
*cp++的执行步聚如下:
(1)++操作符产生cp的一份拷贝
(2)然后++操作符增加cp的值
(3)最后,在cp的拷贝上执行间接访问操作
(注意这里++的优先级比*的高)
指针运算:
int *p, *p1;
p+2 实际上为: p + sizeof(*p)*2
p-2 实际上为: p –sezeof(*p)*2
p2 –p1 实际上为: (p1 –p)/(sizeof(*p1)), 两个指针相减时会执行除法操作,影响效率.
标准允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针进行比较,但不允许与指向数组第1个元素之前的那个内存位置的位指针进行比较.
如:
#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp = &values[0]; vp < &values[N_VALUES];)
*vp++ = 0;
for(vp= &values[N_VALUES-1]; vp>=&values[0]; vp--)