【问题标题】:Undefined Behavior of Postfix or Prefix Increment in Function Calls in C [duplicate]C中函数调用中后缀或前缀增量的未定义行为[重复]
【发布时间】:2014-06-15 14:51:51
【问题描述】:

我在此站点中看到函数调用中的前缀增量或后缀增量可能会导致未定义的行为。我最近经历了其中之一。源代码是这样的:

#include <stdio.h>

void call(int,int,int);
int main()
{
    int a=10;
    call(a,a++,++a);
    printf("****%d %d %d***_\n",a,a++,++a);
    return 0;
}

void call(int x,int y,int z)
{
    printf("%d %d %d",x,y,z);
}

输出为 12 11 12****14 13 14***_。但是,当函数中首先打印 a 时,它不应该是 10 吗?为什么会变成12?另外,为什么 a++ 从 12 减少到 11?有人可以请解释一下吗?谢谢。

【问题讨论】:

标签: c function post-increment pre-increment


【解决方案1】:

C 和 C++ 标准没有指明函数参数的计算顺序。坦率地说,编译器导致参数从右到左或从左到右进行评估是不正确的。

最好的答案是,远离这种“未定义的行为”;因为它可能会导致微妙的可移植性问题。

【讨论】:

  • 我们这里有未定义的行为,它胜过我们可能有的任何未指定的行为实现定义的行为
  • @Deduplicator,感谢您的洞察力。我已经编辑了我的答案以反映这一点。
【解决方案2】:

您的示例代码需要我们考虑两件事:

  1. 未指定函数参数的求值顺序。因此,++aa++ 首先被评估,但它取决于实现。

  2. 多次修改a 的值而修改之间没有序列点也是未定义的行为。

由于第 2 点,您在这里有双重未定义的行为(您做了两次)。注意未定义的行为并不意味着什么都没有发生;这意味着任何事情都可能发生。

call(a,a++,++a); /* UB 1 */
printf("****%d %d %d***_\n",a,a++,++a); /* UB 2 */

【讨论】:

  • 你描述的UB只有一种情况,但是nvm。
  • @Deduplicator 除非用户执行了两次。
  • 以前不是“因为那些点”吗?好吧,现在是(唯一的答案是),所以 +1。
【解决方案3】:

这是未定义的行为,因此完全取决于编译器的实现,以何种顺序完成以下操作:

  1. 提交参数a
  2. 提交参数a++
  3. 提交参数++a
  4. 增加a++a
  5. 增加aa++

编译器唯一知道的是:2. 必须在 5. 之前发生,而 4. 必须在 3. 之前发生。

你正在观察:

++a;
submit argument 2
a++;
submit the other arguments

【讨论】:

  • 我们这里有Undefined Behavior,而不是Unspecified BehaviorImplementation-defined Behavior。这只是错误
  • UB 并不意味着可能的结果以任何方式受到书面子操作的天真重新排序的限制。它是完全未定义的。
  • 假设我们有一个未定义的行为。但是,似乎每一次,a 通过 a++ 增加到 ++a,这使得 10 变为 12。但是,a++ 中已经有 11。而且,++a 里面有 12 个。因此,打印了 12 11 12。 @Deduplicator,为什么我们每次都按照特定的顺序叫它UB?
  • @hayet:之所以这样称呼,是因为规范允许任何事情发生:Anything at all. 在您检查的所有实例中,您在环境中的优化设置的实现总是以相同的方式执行这一事实并不改变任何东西,至多给你一种不合理的自满情绪。
  • #Deduplicator,它澄清了未定义的行为。
【解决方案4】:

不要求a 等于任何东西;这就是未定义行为的含义。完全由编译器以它认为合适的任何顺序评估 callprintf 的参数,因为语言没有指定它们需要评估的顺序。

【讨论】:

  • 实现定义和未指定的行为不是未定义的行为。
  • 请提供语言区分的示例。
  • Chapter 3 Terms, Definitions and Symbols 给出了所有三种行为的定义。 UB 示例:++x+x++,ID 示例:sizeof(int)。未指定行为的示例:“未指定行为的示例是评估函数参数的顺序。”
  • 谢谢;这澄清了问题。
猜你喜欢
  • 2012-10-03
  • 2014-04-30
  • 1970-01-01
  • 1970-01-01
  • 2018-09-08
  • 1970-01-01
  • 2017-12-02
  • 1970-01-01
  • 2014-08-11
相关资源
最近更新 更多