首页 > 代码库 > 《你必须知道的495个C语言问题》笔记--表达式

《你必须知道的495个C语言问题》笔记--表达式

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;
}
编译时:

[root@yanPC ~]# 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

要避免意外,最好的办法是避免在同一个表达式中混用有符号和无符号变量。