2010-03-03 29 views
2

这段代码有一个有趣的错误:顺序分配的评价(有没有发现我的第一个编译器错误?)

some_struct struct_array1[10] = {0}; 
some_struct struct_array2[10] = {0} 
int i; 

for (i = 0; 
    i < sizeof(struct_array1)/sizeof(struct_array1[0]); 
    struct_array1[i].value = struct_array2[i++].value = 1) 
    ; 

对于大多数编译器,上面的代码导致设置在所有的结构的“值”字段相应的数组为1. 但是,对于一个特定的编译器(让我们称之为xcc),struct_array1中的结构体没有正确初始化。所有结构的“值”字段都设置为0,这让我很惊讶。

下面的代码片段按预期工作在所有的编译器:

for (i = 0; 
    i < sizeof(struct_array1)/sizeof(struct_array1[0]); 
    i++) 
{ 
    struct_array1[i].value = struct_array2[i].value = 1; 
} 

现在,我是完全在这里下车,或确实有问题的编译器“XCC”只显示一个错误?

我找不到在第一个代码片段中显示实现特定行为的任何内容;根据我的理解,后缀增量应该优先于赋值,并且赋值应该从右到左进行评估。第一个代码片段应该没有什么奇怪的,只是它有点不可读。

+4

这不是一个编译器错误,它是一个程序员错误:代码涉及未定义的行为,因此无效C – Christoph 2010-03-03 12:00:40

+0

http://catb.org/~esr/faqs/smart-questions.html#id382249 – 2010-03-03 12:03:44

+0

我建议你谷歌上涨未定义的行为。 – 2010-03-03 12:04:46

回答

8

您调用了未定义的行为,因为它修改了i,并且还为了计算新值的目的而取出了它的值,而没有插入的顺序点。

C99标准的相关部分是在6.5节本节:

之前和下一序列 点的对象应具有其存储 值通过的所述 评价改性至多一次之间表达。 此外,先前值应为 只读,以确定存储的值为 。

+0

啊,当然。这并不能解释为什么第二个例子可行,但由于它是未定义的行为,我猜它不一定是一致的:-) – Christoffer 2010-03-03 12:28:51

+0

第二个例子是OK,因为'i'没有被修改 - 它只被读取两次(增量发生在一个单独的表达式中,在一个序列点之后)。 *被修改的两个对象是不同的(所以这也可以)。 – caf 2010-03-03 12:38:45

+0

是的,我实际上有点尴尬,我没有看到我的自我,我想我需要另一双眼睛来发现问题。(为了我的辩护,我想补充一点,我正在审查的建议补丁是500行代码,这只是其中一个问题:-) – Christoffer 2010-03-04 09:36:25

5

struct_array1[i].value = struct_array2[i++].value = 1

我认为这是不确定的行为,因为i++不能保证达到下一个序列点,直到完成所有的副作用。下一个序列点是声明结尾的'想象';。这是一个常见的陷阱,我认为你可以找到很多关于它的主题,只是搜索序列点。

+0

这是真的。从我+1。 – 2010-03-03 12:00:56

0

其实我们并不想为同一个变量执行一个以上的评价,在劲儿

表达。如果我们做了这件事,那将是未定义的行为。

相关问题