2

可能重复:
谁能解释这些未定义的行为(i = i++ + ++i,i = i++,等等……)
下面的宏会给应用程序带来什么问题?

我编写了一个带有宏扩展的示例应用程序,用于在我的 iOS(Objective C 代码)中实现它。

它是这样的:

#define SQUARE(x) ( x * x )
main( )
{
   int i = 3, j, k ;
   j = SQUARE( i++ ) ;
   k = SQUARE( ++i ) ;
   printf ( "\nValue of i++ = %d\nValue of ++i = %d", j, k ) ;
}

输出是:

Value of i++ = 9
Value of ++i = 49

预期输出为:

 Value of i++ = 9
 Value of ++i = 25

我对这个结果感到惊讶。我对这个宏扩展有点困惑。

为什么会这样?请帮我找出原因。

4

3 回答 3

6

您 通过修改不止一次而没有干预序列点来调用未定义的行为。i

在宏替换之后,这两行将如下所示:

   j = ( i++ * i++ ) ;
   k = ( ++i * ++i ) ;
于 2013-01-21T09:37:57.937 回答
6

这确实是未定义的行为(不应依赖于另一个编译器,甚至不应该依赖于同一编译器的下一次运行),因为它在没有序列点的同一语句中将同一变量增加了两次,但这似乎发生在这个案子;

#define SQUARE(x) ( x * x )
j = SQUARE( i++ ) ;
k = SQUARE( ++i ) ;

将扩大到

j = (i++ * i++);     // Compiler could do i * i, then increment twice, or use i * (i + 1), or...  

k = (++i * ++i);     // Same as above

由于这是未定义的行为,编译器可以随意做任何事情(旧版本的 gcc 使程序启动 nethack ;-)。更准确地说:编译器可以自由假设永远不会调用未定义的行为,并确保代码在“正常”情况下正常工作。在意想不到的情况下会发生什么是任何人的赌注。

于 2013-01-21T09:38:24.687 回答
1

这是因为您在两个序列点之间将单个变量增加了两次。因此这是一个未定义的行为

   int i = 3, j, k ;
   j = SQUARE( i++ ) ; // it becomes (i++ * i++)
   k = SQUARE( ++i ) ; // it becomes (++i * ++i)

因此即将到来的输出是未定义的。

您得到的输出是因为在第一次 xpression 之后 i 将被递增两次,因此在第二个表达式中 i 由于预递增而被递增两次,对于上述后递增,它也被递增两次。

j=(i++ * i++)//it comes 3*3 

k=(++i * ++i)// it comes 7 as two increments of above xpression
于 2013-01-21T09:41:59.760 回答