【问题标题】:Different and odd results when using prefix and postfix operators in function arguments [duplicate]在函数参数中使用前缀和后缀运算符时的不同和奇怪的结果[重复]
【发布时间】:2021-07-18 07:20:14
【问题描述】:

代码:

#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 语句中的这些表达式是如何执行的?

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

【问题讨论】:

  • 我的意思是编译器考虑 printf 语句中的这些表达式的顺序 -- 没有定义的顺序。函数参数可以在 C++ 中以任何顺序求值。但是你为什么还要考虑写这样的代码呢?
  • 是否依赖于编译器到编译器?
  • 它可以取决于用于构建代码的不同编译器选项,而不仅仅是不同的编译器。不要写这样的代码,这是底线。
  • 另外,请标记一种语言。 C 和 C++ 是两种不同的语言。
  • 这是一个真正的常见骗局

标签: c printf stdio postfix-operator prefix-operator


【解决方案1】:

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

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

但是,它是可以解释的 正确的评估,而不是不合理或随机的。
(请注意,大多数参数与传递i 相同;i = 18“是”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;

【讨论】:

    【解决方案2】:

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

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

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

    相关标准条目:

    N1570 ISO/IEC 9899:201x C11

    §6.5 表达式:

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

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

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

    §6.5.2.2 函数调用

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

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

    【讨论】:

      【解决方案3】:

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

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

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

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

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

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

      【讨论】:

      • 这种类型的例子通常会在教师试图解释后增量和前增量时出现 -- 如果这就是所显示的内容并试图解释,那么该教师应该被解雇输出完成。
      猜你喜欢
      • 1970-01-01
      • 2018-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多