【问题标题】:Simplest way to determinize a C program确定 C 程序的最简单方法
【发布时间】:2013-08-22 14:17:16
【问题描述】:

考虑下面的 C 程序:

#include <stdio.h>

int f() {
  printf("f");
  return 1;
}

int g() {
  printf("g");
  return 2;
}

int main() {
  return f() + g();
}

根据 C 标准,由于 main 函数中的和包含两个子表达式以及 C99 标准的以下摘录,因此该程序没有单一的确定性行为:

§6.5 (...) 子表达式的求值顺序和顺序 发生了哪些副作用都未指定。

因此,打印fggf 都是该程序的有效输出。在实践中,给定的编译器将选择一个固定的评估顺序(例如,在这种情况下,gcc 从左到右),但如果我想可靠地比较不同编译器之间的输出,我需要确保我的程序有一个定义的行为。

我的问题是:最简单的方法是什么?有没有办法避免包含临时变量(例如,int tmp = f(); return tmp + g();)?

【问题讨论】:

  • 这是一个相当学术的练习。在实践中,您不会对执行此类输出的函数的结果进行求和(或乘、减等)。
  • 另外,编译器不会有固定的评估顺序。如果编译器可以通过重新排序操作进行优化,它会。

标签: c standards


【解决方案1】:

答案直接而简单:避免未指明的行为。

对于您的示例情况,如果main 的返回值无关紧要,您可以使用:

return f(), g();

逗号运算符可以确保操作数从左到右执行。

如果您需要f() + g() 的值,则需要使用临时变量。

【讨论】:

  • @MitchWheat:不,但是 OP 的要求相当牵强。在实践中,您要么这样做,要么使用临时变量来线性化操作。
  • 我在这里看不到未定义的行为。 UB 暗示nasal demons 是可能的。 不是这里的情况。在这个程序中,输出可能正确地是两个可能的输出之一,但绝不是鼻恶魔。
  • @abelenky 所以,“未指明的行为”是正确的词,对吧?
  • 是的,看起来 Wiki 对Unspecified Behavior 的描述比未定义行为更合适。
【解决方案2】:

要强制执行评估顺序,您需要在函数调用之间有一个序列点。

最简单的方法是使用局部变量来存储中间结果。

除非您有深度递归或极其严格的内存限制,否则这很少会成为问题。

【讨论】:

    【解决方案3】:

    不符合标准;最简单的方法是使用临时变量。

    【讨论】:

      猜你喜欢
      • 2012-01-18
      • 2010-09-23
      • 2021-12-26
      • 2017-01-09
      • 1970-01-01
      • 2019-05-09
      • 2010-12-03
      • 1970-01-01
      • 2019-06-25
      相关资源
      最近更新 更多