-3

所以我被这个问题困住了。

int i=5,a;
a=++i + i++ + ++i + i++ - --i;
printf("%d",a);

根据我的说法,'a' 应该是 20。a=6+6+8-8 但是,在执行时我发现答案是 18。我做错了什么?一步一步的解释会很有帮助。

4

5 回答 5

3

这是未定义的行为。一个变量不能在序列点之间多次更改。你的程序可以输出任何东西。任何其他说明的答案都是错误的。

于 2011-10-03T18:57:09.657 回答
3

我已经在我的博客文章中详细描述了这一点:http: //blog.susam.in/2010/05/sequence-points.html

我在这里发布了一些摘录。

在 C 编程论坛中不时地询问特定类型的问题。此类问题有两件事会激怒论坛中经验丰富的程序员。首先,这种类型的问题非常普遍,以至于许多人甚至不想回复它们,即使这意味着发布指向已回答类似问题的另一个线程的链接。其次,更重要的是,即使有人试图提供该问题的正确答案,也有许多其他人会忽略它并用错误的答案填满线程。

这些问题通常涉及查找这样的代码的输出。

#include <stdio.h>

int main()
{
    int i = 5;
    printf("%d %d %d\n", i, i--, ++i);
    return 0;
}

使用 gcc 编译时输出为 5 6 5,使用 Microsoft Visual Studio 附带的 Microsoft C/C++ 编译器编译时输出为 6 6 6。

此类 C 程序的行为是未定义的。在语句中 printf("%d %d %d\n", i, i--, ++i); 和 a += a++ + a++;,分号是唯一的序列点。C 保证给定表达式的所有副作用都由程序中的下一个序列点完成。如果两个或多个具有相互影响的副作用的操作发生在下一个序列点之前,则行为未定义。当使用不同的编译器编译时,此类代码的行为可能会有所不同。

在我引用 ISO/IEC 标准的相关部分之前,让我引用 K&R 的一些内容。在本书的第 2.12 节(评估的优先级和顺序)中,作者写道,

C, like most languages, does not specify the order in which the

计算运算符的操作数。(例外是 &&、||、?: 和 ','。)例如,在类似的语句中

x = f() + g();

f may be evaluated before g or vice versa; thus if either f or g

改变另一个依赖的变量,x 可以依赖于评估的顺序。中间结果可以存储在临时变量中以确保特定的顺序。

他们在本节中提供了另一个示例。

One unhappy situation is typified by the statement

a[i] = i++;

The question is whether the subscript is the old value of i or the

新的。编译器可以用不同的方式解释这一点,并根据他们的解释产生不同的答案。

如果您想了解更多信息,请下载 ISO/IEC 9899 C 标准并转到第 438 页的附录 C – 序列点。它列出了所有的序列点。; 是其中之一。+ 和 ++ 运算符不是序列点。

接下来,阅读第 5.1.2.3 节(程序执行)第 2 点。

Accessing a volatile object, modifying an object, modifying a

文件,或调用执行任何这些操作的函数都是副作用,11)这是执行环境状态的变化。表达式的评估可能会产生副作用。在被称为序列点的执行序列中的某些指定点,之前评估的所有副作用都应该是完整的,并且后续评估的副作用应该没有发生。(序列点的摘要在附件 C 中给出。)

于 2011-10-03T19:00:03.430 回答
1

在 C 的标准中,它明确表示只要遵循优先规则,编译器就可以自由地以任何方式重新排列表达式。这意味着如果你有这个表达式:

x = foo() + bar() + baz()

这三个函数可以按任意顺序调用,并且是合法的。

在旧的 C 标准中,它甚至说编译器可以忽略括号,如果它想:

x = (foo() + bar()) + baz()

强制执行某种评估顺序的唯一可靠方法是使用临时变量:

temp0 = foo();
temp1 = bar();
x = temp0 + temp1 + baz();
于 2011-10-03T18:59:45.880 回答
0

您分配给的表达式a表现出未定义的行为,特别是递增/递减操作应用于其操作数的顺序。

于 2011-10-03T18:57:43.977 回答
0

取决于编译器执行所有操作的顺序。由于它依赖于编译器实现,因此没有“正确”的答案。

例如,严格左->右:

a = (++i) + (i++) + (++i) + (i++) - (--i);
     first   second  third  fourth  fifth
a = (6) + (6) + (8) + (8) - (7) = 21;

向右->向左:

a = (++i) + (i++) + (++i) + (i++) - (--i);
     fifth   fourth third   second    first
a =  6 + 5 + 5 + 4 - 4 = 16;
于 2011-10-03T19:01:09.343 回答