-3

代码:

#include <stdio.h>

int main()
{
    int i = 3;
    printf("%d %d %d %d %d\n",i = 7,--i,i = 18, i+5, i = 0);
    printf("%d %d %d %d %d\n",i = 7,i--,i = 18, i+5, i = 0);

    return 0;
}  

输出:

7 7 7 5 7
7 18 7 5 7

为什么我得到这个输出,谁能向我解释一下printf语句中的这些表达式是如何执行的?

我的意思是,编译器按什么顺序考虑?

4

3 回答 3

1

这里最大i的问题是由于缺少序列点而在调用未定义行为时所做的更改。

表现出未定义行为的程序对编译过程应该如何发生没有任何要求,编译器可以按照它认为合适的方式处理它,不同的编译器甚至同一编译器的不同版本都会产生不同的结果。

虽然这不是必需的,但他们通常做的一件事是产生一些警告,前提是启用警告标志,有些甚至不需要,demo

相关标准条目:

N1570 ISO/IEC 9899:201x C11

§6.5 表达式:

2 -如果标量对象的副作用相对于同一标量对象的不同副作用或使用同一标量对象的值的值计算是未排序的,则行为未定义。如果表达式的子表达式有多个允许的排序,则如果在任何排序中出现这种未排序的副作用,则行为未定义。

需要明确的是,逗号运算符不是序列点。

我还应该注意,函数参数的评估顺序是未指定的。

§6.5.2.2 函数调用

10 -在函数指示符和实际参数的评估之后但在实际调用之前有一个序列点。调用函数(包括其他函数调用)中的每个求值,如果在被调用函数的主体执行之前或之后没有特别排序,则相对于被调用函数的执行是不确定的。

正如已经指出的那样,这不是您应该向任何人展示的代码,在这种情况下是出于学习目的。

于 2021-04-24T09:18:12.877 回答
1

参数的评估顺序未指定,对同一对象的未排序修改具有未定义的行为。

所以,正式地,推理你的代码是没有意义的。

但是,它可以通过正确的评估来解释,而不是不合理或随机的。
(请注意,大多数参数与传递i; i = 18"is"相同i,而不是 18。)

首先:

i = 0;
int new_variable = i + 5;
i = 18;
i -= 1;
i = 7;
printf("%d %d %d %d %d\n", i, i, i, new_variable, i);

第二:

i = 0;
int new_variable = i + 5;
i = 18;
int previous_i = i;
i = 7;
printf("%d %d %d %d %d\n", i, previous_i, i, new_variable, i);
i -= 1;
于 2021-04-24T10:04:10.770 回答
0

这是一个非常奇怪的代码,你永远不要想写这样的代码,它会带来不必要的混乱。

函数参数可以根据编译器设置以任何顺序进行评估,因此此代码的输出可能会因编译器和设置而异。

我假设你在某个学校的课堂上看到过这段代码,这种类型的例子通常会在老师试图解释后增量和前增量时出现。

请理解前增量和后增量差异拳头:

  • ++x(pre-increment) 意思是“增加变量;表达式的值是最终值”
  • x++(post-increment) 意思是“记住原始值,然后递增变量;表达式的值就是原始值”

编辑:更改解释以不引起混淆,输出可能因多个变量而异。

于 2021-04-24T09:02:16.647 回答