【问题标题】:Order of assignment evaluation (Have I found my first compiler bug?)赋值评估的顺序(我发现我的第一个编译器错误了吗?)
【发布时间】:2010-03-03 11:54:49
【问题描述】:

这段代码有一个有趣的错误:

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,这让我很惊讶。

以下代码 sn-p 在所有编译器上都按预期工作:

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

现在,我完全离开这里了吗,还是有问题的编译器“xcc”只是显示了一个错误?

我在第一个代码 sn-p 中找不到任何显示特定于实现的行为;据我了解,后缀增量应该优先于分配,并且分配应该从右到左进行评估。第一个代码 sn-p 应该没有什么奇怪的,只是有点不可读。

【问题讨论】:

标签: c c99 undefined-behavior


【解决方案1】:

您调用了未定义的行为,因为它修改了i,并且还为计算新值以外的目的获取其值,而没有中间序列点。

C99标准的相关部分是6.5节中的这一条款:

在上一个序列和下一个序列之间 点一个对象应该有它的存储 值最多修改一次 表达式的评估。 此外,先验值应为 只读以确定要为的值 存储。

【讨论】:

  • 啊,当然。这并不能解释为什么第二个示例有效,但由于它是未定义的行为,我猜它不必是一致的 :-)
  • 第二个例子没问题,因为i没有被修改——它只是被读取了两次(增量发生在一个单独的表达式中,在一个序列点之后)。 修改的两个对象是不同的(所以也可以)。
  • 是的,我实际上有点尴尬,我没有亲眼看到它,我想我需要另一双眼睛来发现问题。 (为了我的辩护,我想补充一点,我正在审查的提议的补丁是大约 500 行代码,这只是问题之一 :-)
【解决方案2】:

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

我认为这是未定义的行为,因为在到达下一个序列点之前,i++ 不能保证完成其所有副作用。下一个序列点是语句末尾的“虚构”;。这是一个常见的陷阱,我认为您可以找到许多与它相关的 SO 主题,只需搜索序列点即可。

【讨论】:

    【解决方案3】:

    实际上我们不应该对同一个变量执行多个评估,在signle中

    表达式。如果我们这样做,那将是未定义的行为。

    【讨论】:

      猜你喜欢
      • 2011-07-10
      • 2022-01-20
      • 2012-02-02
      • 1970-01-01
      • 2011-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多