C在短路表达式中对同一变量进行多次赋值

Mad*_*ist 6 c

我有三个变量:a, b, c。假设它们是整数。我想按特定顺序在其中找到第一个非零值,而不需要循环。以下似乎有效,但我不确定这是因为我很幸运,还是因为语言保证了这一点:

int main(int argc, char *argv[]) {
    int a = 0;
    int b = 3;
    int c = 5;
    int test;

    if ((test = a) != 0 || (test = b) != 0 || (test = c) != 0) {
        printf("First non-zero: %d\n", test);
    } else {
        printf("All zero!\n");
    }

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

此处显示的带有短路的重复分配是否保证按预期工作,还是我遗漏了什么?

这可能是一个可以接受三个字母答案的地方,但两个字母的答案可能需要更多解释。

Jac*_*son 6

它会!

由于 OR 运算符的性质,如果任何条件为真,则测试停止。

因此我认为你所做的基本上相当于:

test = a != 0 ? a : b != 0 ? b : c != 0 ? c : 0;
printf("%d\n",test);
Run Code Online (Sandbox Code Playgroud)

但是你的看起来不错。

[更新]

根据 chqrlie 所提到的,它可以进一步简化为:

test = a ? a : b ? b : c;
Run Code Online (Sandbox Code Playgroud)


Lun*_*din 2

该代码是非常糟糕的做法,但保证可以正常工作。

这是因为||and&&运算符具有特殊的特性 - 与 C 中的大多数运算符不同,它们保证左操作数的计算在右操作数的计算之前排序(执行)。这就是代码有效的原因。还可以保证,如果足以评估左侧操作数(“短路”),则不会评估右侧操作数。C17 6.5.14/4 中总结:

与按位 | 不同 运算符,|| 运算符保证从左到右评估;如果计算第二个操作数,则在第一个和第二个操作数的计算之间存在序列点。如果第一个操作数比较后不等于 0,则不计算第二个操作数。

“序列点”是这里的关键,它赋予表达式确定性的结果。

如果您使用了几乎任何其他运算符(例如 bitwise ),那么结果将是未定义的,因为您对同一表达式中的|同一变量有多个副作用(赋值) 。test

同一算法的更完善版本将涉及将数据存储在数组中并循环遍历它。