1.怎样才能避免这些未定义的求值顺序问题呢?
有几条简单的规则:
1.确保一个表达式最多只修改一个对象:一个简单变量、一个数组或者一个指针指向的位置。
2.如果一个对象在一个表达式中出现一次以上而且在表达式中被修改,则要确保对该对象的所有读访问都被用于计算它的
最终值。这条规则允许表达式i=i+1,尽管i出现了两次而且被修改了,但对i的旧值读取是用于计算i的新值。
3.如果想破坏第一条规则,就要确保修改的对象互不相同。同时,尽量限制到最多2至3个修改并参照下面例子的风格。在
这条规则下,c=*p++是合法的。因为修改了两个对象。类似的,c=a[i++]和a[i++]=c也是允许的。
4.如果在两次修改或修改和访问之间置入定义的序列点操作符(||,&&,?:或者逗号),则可以破坏第一条规则和第二条
规则。如:
(c = getchar()) != EOF && c != ‘\n‘
2.需要根据条件把一个复杂的表达式赋给两个变量中的一个。可以用下面这样的代码吗?
((condition)?a:b) = complicated_expression;
不能,?:操作符跟多数操作符一样,可以生成一个值,而不是被赋值,换言之,?:不能生成一个左值。如果真的需要,可以
试试下面这样的代码:
*((condition)?&a:&b) = complicated_expression;
实践:
#include <stdio.h> int main(void) { int x = 1,a = 0, b = 0; (x>0)?a:b = 1; printf("%d,%d\n",a,b); return 0; }
编译时:
[[email protected] ~]# gcc a.c
a.c: In function ‘main‘:
a.c:6: error: invalid lvalue in assignment
修改后:
#include <stdio.h> int main(void) { int x = 1,a = 0, b = 0; *((x>0)?&a:&b) = 1; printf("%d,%d\n",a,b); return 0; }
运行结果:
1,0
3.无符号保护和值保护规则的区别在哪里?
在“无符号保护”规则下,提升的类型总是无符号的。这个规则的有点简单明了,但是结果可能会出人意料。
在“值保护”规则下,转换取决于原来类型的提升类型的实际大小。如果提升类型的确较大,就是说它可以用有符号值表达
原来类型的所有无符号值--则提升后的类型为有符号类型。如果这种类型的大小实际是一样的,则提升后的类型为无符号
型。
下面显示了无符号保护规则下可能出现的意外。
unsigned short us = 10; int i = -5; if (i > us){ printf("whoops!\n"); }
在无符号保护规则下us被提升为unsigned int了。通常的整型提升规则标明,如果unsigned int和int出现在二元操作符两侧,
则两个操作数都会转换成unsigned int。因此也被转成unsigned int了。i的原值-5被转化成一个很大的无符号值,这个值比
10大,因此会打印whoops。
在值保护规则下,如果整型比短整型大,则us会被转换成普通型,而i则仍然是普通的整型。这样表达式不为真,也不打印
出任何内容。
可是值保护规则也不能防止所有的意外。详细可以参考以前写过的一个帖子:
http://blog.csdn.net/todd911/article/details/6643627
要避免意外,最好的办法是避免在同一个表达式中混用有符号和无符号变量。
《你必须知道的495个C语言问题》笔记--表达式