如何根据操作数的顺序进行C赋值

yan*_*nep 0 c language-lawyer

我相信大多数人都知道C没有指定运算符(如+)的操作数将被评估.

x = exp1 + exp2可以通过首先评估exp1,然后是exp2,然后添加结果来评估Eg .但是,它可能首先评估exp2.

我将如何进行C赋值,将1或2分配给x,具体取决于是否首先计算+的左或右操作数?

Lun*_*din 6

编写这样一个表达式的问题是你不能在其中写入两次相同的变量,或者代码将调用未定义的行为,这意味着会有一个错误,任何事情都可能发生.如果在表达式中修改了变量,则不允许在同一表达式中再次访问该相同变量,除非访问由所谓的序列点分隔.(C11 6.5/2)有关详细信息,请参阅此处.

所以我们不能写这样的代码:

// BAD CODE, undefined behavior
_Bool first=false;
x = (first?(first=true,exp1):0) + (first?(first=true,exp2):0);
Run Code Online (Sandbox Code Playgroud)

此代码调用了未定义的行为,因为first对表达式的差异位置之间的访问是未排序的.


但是,可以通过使用函数来实现类似的代码.每次调用函数时,在调用函数之前,在参数求值之后都会有一个序列点.在函数返回之前还有另一个序列点.所以这样的代码是可能的:

n = expr(1) + expr(2)
Run Code Online (Sandbox Code Playgroud)

这仅仅具有未指定的行为 - 因为未指定对操作数的评估.但是在任何地方都没有无序的访问,这意味着代码不会崩溃等等.我们根本无法知道或假设它会给出什么结果.例:

#include <stdio.h>

static int first=0;

int expr (int n)
{
  if(first == 0)
  {
    first = n;
    return first;
  }

  return 0;
}

int main (void)
{
  int n;
  printf("%d\n", n = expr(1) + expr(2)); // unspecified order of evaluation
  first=0;
  printf("%d\n", n = expr(1) + expr(2)); // unspecified order of evaluation

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

这给了1 1我的系统输出,但它也可能给出了输出1 2,2 1或者2 2.下次我执行程序时,它可能会给出不同的结果 - 我们不能假设任何东西,除了程序将以未记录的方式确定性地运行.

这是未指定的主要原因,它允许不同的编译器根据情况不同地优化其表达式解析树.这反过来又实现了最快的执行时间和/或编译时间.