C语言中操作数的顺序

4

假设你在C语言中有x = exp1 + exp2。它可能是通过首先计算exp1再计算exp2并将结果相加来评估的,但也可能先计算exp2。

如何找出哪个表达式先被计算?我想要根据先计算的表达式使x等于1/2。

有什么想法吗?


6
这听起来有点像 XY问题 - 我正在努力想出为什么有人会想要这样做:/ - Oliver Charlesworth
9
你做不到。你无法像那样控制编译器。你需要编写代码,使得这种情况无关紧要。 - Jonathan Leffler
6
通过调用具有副作用的函数来测试exp1和exp2 (例如打印输出) 可以很容易地找出它们的值。但是,无论如何都不能依赖于这些值始终按相同顺序返回。 - Ctx
6
@Ketameme 我真的怀疑你是否完全理解了任务。 - Ctx
4
...但如果你真的这样做了,@Ketameme,请把你的教练送到这里来接受一些严厉的惩罚。 - John Bollinger
显示剩余11条评论
2个回答

5

好的,你可以这样做:

#include <stdbool.h>
#include <stdio.h>

static int first(int value)
{
  static bool first = false;
  if (!first)
  {
    first = true;
    return value;
  }
  return 0;
}

int main(void)
{
  const int x = first(1) + first(2);
  printf("got %d\n", x);
}

在ideone.com上,我得到了1
需要注意的是,这并不能证明什么,因为这里没有定义行为。 C99草案在6.5表达式第3段中说:
“运算符和操作数的分组由语法表示。(72)除非稍后指定(对于函数调用(), &&, ||, ?:和逗号运算符),否则子表达式的求值顺序和副作用发生的顺序都是未指定的。”

类似于答案为2的情况是在什么时候发生的,这只取决于编译器如何处理它吗? - Ketameme
2
@Ketameme 注意这个评论。代码的后续运行可能会导致不同的答案 - 所以在那种情况下不是编译器问题。Unwind:对于问题来说是一个简单而好的回答,即使OP的更高级目标不明确。 - chux - Reinstate Monica

0
你如何确定哪一边会先被评估?
通常情况下,这并未被标准规定。C11 6.5/3:
"除非另有规定,子表达式的副作用和值计算是无序的。"
"..."
"在程序执行期间多次评估的表达式中,在不同的评估中无需一致地执行其子表达式的无序和不确定排序评估。"
"另外规定" 指的是一些特殊情况,其中规定了评估顺序,即对于以下运算符: || && ?: , 这些运算符保证从左到右进行评估。
如我们从引用的说明中所看到的那样,我们甚至不能知道相同的程序是否始终以相同的方式处理相同的表达式。这就是所谓的 "未指定行为",这意味着编译器将按照几种明确定义的方式来执行,但我们永远无法知道或假设哪种方式。您应始终编写自己的程序,使评估顺序无关紧要。
如果你想要玩弄打印编译器决定评估特定表达式的顺序的代码(这一次),你可以这样做:
#include <stdio.h>

int func(void)
{
  static int x=0;
  return x++;
}

int main (void)
{
  printf("%d", func() << func());
}

这将会给出 0<<1 == 0(从左到右)或者 1<<0 == 1(从右到左)。但是这样的代码没有实际用途。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接