提问者:小点点

为什么这些构造使用预增量和后增量的未定义行为?


#include <stdio.h>

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

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

   volatile int u = 0;
   u = u++ + ++u;
   printf("%d\n", u); // 1

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

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

   int w = 0;
   printf("%d %d\n", ++w, w); // shouldn't this print 1 1

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

共1个答案

匿名用户

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

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

那么,考虑到这一点,为什么这些是“问题”呢?语言明确地说,某些事情导致未定义的行为。没有问题,没有“应该”的牵扯。如果当一个涉及的变量声明为volatile时未定义的行为发生了变化,那么这并不能证明或改变任何事情。未定义;你无法对这种行为进行推理。

你最有趣的例子是

u = (u++);

是一个未定义行为的教科书例子(参见维基百科关于序列点的条目)。