为什么这些构造(使用++)在C中的未定义行为?

#include <stdio.h>

int main(void)
{
   int i = 0;
   i = i++ + ++i;
   printf("%dn", i); // 3

   i = 1;
   i = (i++);
   printf("%dn", i); // 2 Should be 1, no ?

   volatile int u = 0;
   u = u++ + ++u;
   printf("%dn", u); // 1

   u = 1;
   u = (u++);
   printf("%dn", u); // 2 Should also be one, no ?

   register int v = 0;
   v = v++ + ++v;
   printf("%dn", v); // 3 (Should be the same as u ?)

   int w = 0;
   printf("%d %d %dn", w++, ++w, w); // shouldn't this print 0 2 2

   int x[2] = { 5, 8 }, y = 0;
   x[y] = y ++;
   printf("%d %dn", x[0], x[1]); // shouldn't this print 0 8? or 5 0?
}

C具有未定义行为的概念,即某些语言结构在语法上是有效的,但无法预测代码运行时的行为。

据我所知,该标准没有明确说明为什么存在未定义行为的概念。 在我看来,这只是因为语言设计者希望在语义上有一些余地,而不是要求所有实现都以完全相同的方式处理整数溢出,这很可能会带来严重的性能成本,他们只是留下行为未定义,所以如果你写代码导致整数溢出,任何事情都可能发生。

所以,考虑到这一点,为什么这些“问题”? 该语言清楚地表明,某些事情导致未定义的行为。 没有问题,没有“应该”涉及。 如果未定义的行为在其中一个涉及的变量被声明为volatile发生改变,那么它不会证明或改变任何内容。 它是不确定的; 你无法推断行为。

你最有趣的例子,与

u = (u++);

是未定义行为的文本示例(请参阅维基百科关于顺序点的条目)。


只需编译和反汇编你的代码行,如果你很想知道你到底得到了什么。

这就是我在我的机器上得到的结果,以及我认为正在发生的事情:

$ cat evil.c
void evil(){
  int i = 0;
  i+= i++ + ++i;
}
$ gcc evil.c -c -o evil.bin
$ gdb evil.bin
(gdb) disassemble evil
Dump of assembler code for function evil:
   0x00000000 <+0>:   push   %ebp
   0x00000001 <+1>:   mov    %esp,%ebp
   0x00000003 <+3>:   sub    $0x10,%esp
   0x00000006 <+6>:   movl   $0x0,-0x4(%ebp)  // i = 0   i = 0
   0x0000000d <+13>:  addl   $0x1,-0x4(%ebp)  // i++     i = 1
   0x00000011 <+17>:  mov    -0x4(%ebp),%eax  // j = i   i = 1  j = 1
   0x00000014 <+20>:  add    %eax,%eax        // j += j  i = 1  j = 2
   0x00000016 <+22>:  add    %eax,-0x4(%ebp)  // i += j  i = 3
   0x00000019 <+25>:  addl   $0x1,-0x4(%ebp)  // i++     i = 4
   0x0000001d <+29>:  leave  
   0x0000001e <+30>:  ret
End of assembler dump.

(我...假设0x00000014指令是某种编译器优化?)


我认为C99标准的相关部分是6.5表达式,§2

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

和6.5.16作业操作员,§4:

操作数的评估顺序未指定。 如果尝试修改赋值运算符的结果或在下一个顺序点之后访问它,则行为是未定义的。

链接地址: http://www.djcxy.com/p/12733.html

上一篇: Why are these constructs (using ++) undefined behavior in C?

下一篇: Unsequenced value computations (a.k.a sequence points)