42

我需要编写表格的声明

a = a || expr;

whereexpr应该被评估并且没有设置分配给aiff的结果a。这依赖于逻辑 OR 的短路功能。

当然,写上面的更短的方法是

a ||= expr;

但是(令我惊讶的是)C 没有逻辑赋值运算符。

所以我的问题是双重的。首先,是否有更短的方法可以用标准 C 编写第一条语句(三元运算符更糟——a = a ? a : expr需要我拼出a三次)。

其次,为什么 C 语言中没有逻辑赋值?我能想到的可能原因是:

  • 它使语法更难解析?
  • 这些情况下处理短路有一些微妙之处吗?
  • 它被认为是多余的(但这不是反对所有运算符分配的论点吗?)

编辑

请解开这个问题,因为:

  • 它所链接的问题(作为所谓的副本)尚未得到答复。该问题的(已接受)答案指出||=不存在,因为重复了|=. 那是错误的答案。|=不会短路。

  • C 和 C++ 不是同一种语言。我想知道为什么 C 没有它。事实上,派生语言如 C++,尤其是 Java(没有像 Edmund 的回答中所建议的那样受到遗留代码问题的困扰)这一事实使这个问题变得更加有趣。

编辑 2

现在看来我的初衷是错误的。在语句中a = a || expr(其中a是整数并expr返回一个整数值,首先两者aexpr都将被隐式转换为“布尔值”,然后“布尔”值将被分配给a。这将是不正确的 - 整数值将丢失。谢谢,延斯和埃德蒙。

因此,对于问题的第一部分,正确的方法,而不是替代方案:),编码我的意图是:

if (!a) a = expr;

或者

a = a ? a : expr;

它们应该被优化相同(我认为),但我个人更喜欢第一个(因为它少了一个a要输入的内容)。

但是,问题的第二部分仍然存在。Jens 和 Edmund 关于a ||= expra = a || expr. 分配案例可以简单地视为正常案例:

  • 转换a为布尔值
  • 如果为真,则整个表达式的值变为等于布尔值a
  • 否则评估expr,将结果转换为布尔值,分配给a,并返回它

对于分配和正常情况,上述步骤似乎是相同的。

4

5 回答 5

9

a ||= expr由于对其等效的短路评估是有问题的a = a || expr

要具有a ||= expra = a || expr考虑 OP 的断言这样的功能:

“在语句a = a || expr...中,首先 a 和 expr 都将隐式转换为“布尔值”,

这并不完全正确。 如果计算结果为 ,expr则不会被转换。这会有所不同,应该是影响程序状态的或或某些功能。atrueexprscanf()rand()

诸如此类的代码a ||= scanf("%d", &i) != 1;只会尝试扫描a. 尽管可以以这种方式扩展语言,但在当前集合中添加短路运算符||可能&&会导致比清晰的简化更多的编码问题。

另一方面:一种快速(如果被混淆)编写代码的方法,其中函数在错误时返回非零代码。

// Perform functions until an error occurs.
bool error = foo1();
error &&= foo2();  // Only valid if C was extended with &&=
error &&= foo3();
于 2015-07-14T21:31:05.217 回答
5

因为运算符的返回类型||&&它们的左参数类型不一样。

||and的返回类型&&始终为int1,而 left 参数可以是任何整数、浮点或指针类型。操作数也不必是同一类型。因此,定义x ||= yasx = x || yx &&= yasx = x && y将与其他增强的赋值一致,将无法将结果存储在大多数类型的参数中。

您可以提出其他定义,例如x ||= yasif(!x) x = yx &&= yas if(!y) x = y,但这并不十分明显,也不是那么有用,因此不包括在内。

1在 C++ 中是bool.

于 2014-04-16T12:28:44.547 回答
3

我找不到任何特定的原因,为什么运营商不存在(在 C99 中)。

所以我能找到的唯一原因是,C89 中没有布尔类型,而这些布尔运算符旨在仅用于if's.

例子:

int i = 5;

/* This should not make any difference,
   since or'ing with false, shouldn't change
   the value... dib di dib diddy...*/
i ||= 0; /* Actually: i = i || 0, which gives 'true' */

i现在是“1”,这对大多数人来说是非常违反直觉的。

如果没有布尔类型,该运算符显然不会带来任何清晰性或编码改进,这会使与另一个运算符进行或运算。

在我看来,a ||= b;as的实现if(!a) a = b;非常简单,并且已经由例如 Lua 实现。

所以你的问题似乎有点,为什么 C 是按照它的设计方式设计的。如果这个问题是关于 C++ 的,你可以例如问 Bjarne Stroustrup 并问他,他做了什么。由于情况并非如此,在我看来这似乎是一条死胡同,因为标准已经写了很久了,你不能再问别人了,为什么是 h***。

另一方面,这个不完整的运算符集应该(在我看来)已经使用与您的符号类似的符号变得完整,因为在我看来,没有理由反对它。

我希望我能帮上一点忙。

于 2015-02-26T10:53:44.610 回答
3

我想简单的答案是||一个布尔运算符:在 C 中,“布尔”是 0 或 1。操作数被隐式转换为布尔值(我没有检查过规范实际上是这样说的,但这就是 C 的行为方式),结果是一个布尔值。

改变语义来支持这种模式很可能是可行的——直到有人依赖于 ||做它一直在做的事情。

于 2010-08-17T09:38:48.197 回答
0

一个简单的解释是这样的。

bool resultsComputeAll = false;
bool resultsUntilFirst = false;
for (int i = 0; i < 10; ++i) {
    resultsComputeAll = compute(i) || resultsComputeAll;
    resultsUntilFirst = resultsUntilFirst || compute(i);
}

会是哪一个result ||= compute(i)?它是模棱两可的,所以最好不要定义。

于 2021-08-12T17:34:42.153 回答