我不明白这段代码的输出

时间:2014-02-19 17:22:04

标签: c post-increment pre-increment

我正在学习C,我的老师给了我们一些功课。我们必须确定一些代码的输出。我不明白y=4的方式。

代码如下

int main() {

    int w = 3, y = 3;
    printf("w = %i\n", --w + w--);
    printf("y = %i\n\n", y = w + y++);

    return 0;
}

4 个答案:

答案 0 :(得分:5)

由于您在两个序列点之间修改变量值两次,因此行为未定义。

您应该阅读有关序列点http://en.wikipedia.org/wiki/Sequence_point的更多信息。这就是标准所说的:

  

在称为序列点的执行序列中的某些特定点处,先前评估的所有副作用应完整,并且不会发生后续评估的副作用。

答案 1 :(得分:4)

让我以重要的公共服务公告为前言:

  

当你的编译器给你一个警告,任何警告时,你应该注意它。您的问题中的代码示例会产生未定义的行为 - 换句话说,C标准并不保证每个编译器在给定代码时都会给出相同的结果。这总是一件坏事。

除此之外,这里是对正在发生的事情的解释。

我稍微修改了你的代码以查看w:

的中间值
#include <stdio.h>

int main(void) {

    int w = 3, y = 3;
    printf("w = %i\n", --w + w--);
    printf("w is actually %d\n", w);
    printf("y = %i\n\n", y = w + y++);

    return 0;
}

我的编译器抱怨此代码时出现以下警告:

order.c:6:24: warning: multiple unsequenced modifications to 'w' [-Wunsequenced]
    printf("w = %i\n", --w + w--);
                       ^      ~~
order.c:8:35: warning: multiple unsequenced modifications to 'y' [-Wunsequenced]
    printf("y = %i\n\n", y = w + y++);
                           ~      ^
2 warnings generated.

输出

w = 4
w is actually 1
y = 4

发生了什么事?由于编译器从左到右解析语句,语句

--w + w--

似乎导致以下步骤(对于我的编译器):

--w  : decrement w, it is now 2
w--  : use the value of '2', but decrement w when you are done

结果是总和为2+2,第一行打印4,但在求和之后,w递减为1。但是你不能依赖这种行为 - 这就是编译器发出警告的原因。正如Eric Postpischil所指出的,可能存在执行顺序可能不同的情况。 “不要这样做”是底线 - 你正在追求未定义的行为。

请注意,您的程序打印w equals 4这一事实并不意味着任何时候都是如此。如您所见,当您实际打印出w时,它是1。

假设编译器按上述顺序执行了这些语句,我们转到下一行:

y = w + y++

我们从w = 1y = 3开始。这两者的总和是4,这是表达式的值

y = w + y++

因此是印刷品(4)。

作为副作用,y递增。碰巧的是,无论哪种方式,y的值最后都是4。如果您更改代码以便从w = 5开始,则最终会得到y = 6。换句话说,y++赋值覆盖了y =的效果。

答案 2 :(得分:3)

未定义的行为

此代码中至少有这两部分存在未定义的行为(如Why are these constructs (using ++) undefined behavior?中所述):

--w + w--

y = w + y++

这意味着您获得的结果不可移植或无法保证。

说谎代码

除了未定义的行为之外,输出实际上就在于你。 printf("w = %i\n", --w + w--);看起来正在打印w的值(因为它打印w = …),但它不会打印w的值,而是打印{{1}的值(这是未定义的,所以它实际上打印了编译器编译--w + w--的任何值)。

那么--w + w--的价值是什么?

您的编译器为w生成的代码具有副作用,使--w + w--的值为w,因为它原来是{{1}并且13都会减少--w。但是,w--(在您的编译器生成的代码中,基于您获得的输出,w。可能导致此问题的原因是什么?可以先评估--w + w--,将4--w递减到w,然后返回{em>新值3,是2。然后可以评估w,将2w--递减到w,但会返回2的原始值,是1w2的总和当然是2

因此,2的值为4--w + w--的新值为4

w会发生什么?

1的新值为y,因此当您执行时(回想w的值为1):

y

3的副作用是printf("y = %i\n\n", y = w + y++); 递增(但是在分配之前或之后是否发生这种情况尚未定义),但表达式的是之前的y++值,在本例中为y。因此,您要添加y,其值为3,以及w,即1。然后,您 y++分配给3,并且该分配的值为4,因此您将获得y作为输出。 4中仍然存在可能未定义的行为,因为当 4的增量应该发生时,不明确:在分配之前或之后?

答案 3 :(得分:1)

您的老师正在承担特定的评估顺序,但该语言无法保证。

假设严格的从左到右的评估,假设立即应用副作用,那么给出wy的起始值,会发生以下情况:

  1. --w评估为w-1(2),副作用递减w; w现在是2
  2. w--评估为w(2),副作用递减w; w现在是1
  3. 作为1和2的结果,--w + w--评估为4
  4. y++评估为y,副作用增加y; y现在是4
  5. 作为4的结果,w + y++评估为1 + 3或4
  6. 作为5的结果,y = w + y++将{4}分配给y
  7. BUT ...

    正如我上面所说,这种行为不受语言保证;除少数特定情况外,表达式中的评估顺序为未指定,因此y为4只是许多可能结果中的一个,所有就语言而言,它们被认为是同等正确的。

    任何表达式的行为,它采用以下形式(++--,包括前缀和后缀):

    x++ + x++   
    a[i++] = i
    y = y++
    

    未定义。同样,法案的行为如

    foo(y++, y++);
    

    也未定义。