为什么C没有逻辑赋值运算符?

发布于 2024-09-14 12:12:50 字数 1578 浏览 8 评论 0原文

我需要编写一个如下形式的语句

a = a || expr;

,其中应评估 expr 并将结果分配给 a iff 未设置 a 。这依赖于逻辑或的短路能力。

当然,编写上述代码的较短方法是,

a ||= expr;

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

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

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

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

编辑

请解锁此问题,因为:

  • 它已链接到的问题(据称是重复的)尚未得到答复。该问题的(已接受)答案指出 ||= 不存在,因为重复了 |= 的功能。这是错误的答案。 |= 不会短路。

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

编辑2

现在看来我的初衷是错误的。在语句 a = a || 中expr (其中 a 是整数,expr 返回整数值,首先是 aexpr将隐式转换为“布尔值”,然后将“布尔值”分配给a。这将是不正确的 - 谢谢 Jens 和 Edmund

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

if (!a) a = expr;

或者

a = a ? a : expr;

它们应该进行相同的优化(我认为),尽管我个人更喜欢第一个(因为它少了一个 a 输入)。

然而,问题的第二部分仍然存在。 Jens 和 Edmund 就 a ||= expr 中的歧义给出的论点同样适用于 a = a ||表达式。赋值情况可以简单地视为普通情况:

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

上面的步骤对于赋值和正常情况似乎是相同的。

I had the need to code a statement of the form

a = a || expr;

where expr should be evaluated and the result be assigned to a iff a is not set. this relies on the logical OR's short-circuiting capabilities.

The shorter way to write the above would, of course, be

a ||= expr;

but (to my surprise) C does not have logical assignment operators.

So my question is twofold. First, is there a shorter way to write the first statement in standard C (the ternary operator is even worse - a = a ? a : expr requires me to spell out a thrice).

Secondly, why aren't there logical assignments in C? The possible reasons I could think of are:

  • it makes the grammar harder to parse?
  • there is some subtlety in handling short-circuiting for these cases?
  • it was considered superfluous (but isn't that an argument against ALL the operator assignments?)

EDIT

Please unlock this question because:

  • The question it has been linked to (as a alleged duplicate of) HAS NOT BEEN ANSWERED. The (accepted) answer to that question states that ||= is not present because duplicates the functionality of |=. That is the wrong answer. |= does not short-circuit.

  • C and C++ are NOT the same languages. I wish to know why C doesn't have it. In fact, the fact that derived languages like C++ and, particularly, Java (which did not suffer from the problems of legacy code as has been suggested in Edmund's answer) makes the question even more interesting.

EDIT 2

It now seems like my original intent was wrong. In the statement a = a || expr (where a is integral and expr returns an integral value, first both a and expr will be implicitly converted to "booleans", and then the "boolean" value will be assigned to a. This will be incorrect — the integral value will be lost. Thanks, Jens and Edmund.

So for the first part of the question, the correct ways, not alternatives :), to code my intention would be:

if (!a) a = expr;

or

a = a ? a : expr;

they should be optimized the same (I think) though personally I would prefer the first one (because it has one less a to type).

However, the second part of the question still remains. The arguments that Jens and Edmund about have given about the ambiguity in a ||= expr apply equally well to a = a || expr. the assignment case can simply be treated as the normal one:

  • convert a to boolean
  • if it is true, the value of the entire expression becomes equal to the boolean value of a
  • otherwise evaluate expr, convert result to boolean, assign to a, and return it

The steps above seem to be the same for both the assignment and normal case.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

北渚 2024-09-21 12:12:50

a ||= expr 由于对其等价 a = a || 的短路求值而存在问题。表达式

拥有像 a = a || 这样的 a ||= expr 函数expr 考虑OP的断言:

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

这不太正确。如果 a 计算结果为 true,则 expr 将不会被转换。如果 exprscanf()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();

a ||= expr is problematic due to short circuit evaluation of its equivalent a = a || expr.

To have a ||= expr function like a = a || expr consider OP's assertion:

"In the statement a = a || expr ..., first both a and expr will be implicitly converted to "booleans","

This is not quite correct. expr will not be converted if a evaluates to true. This would make a difference should expr be something like scanf() or rand() or some function that affected the state of the program.

Code such as a ||= scanf("%d", &i) != 1; would only attempt to scan data with a false value in a. Although it would be possible to extend the language this way, additional short-circuit operators to the current set of || and && would likely cause more coding problems than clear simplifications.

On the other hand: A quick, if obfuscated, way to write code where functions return non-zero codes on error.

// Perform functions until an error occurs.
bool error = foo1();
error &&= foo2();  // Only valid if C was extended with &&=
error &&= foo3();
戒ㄋ 2024-09-21 12:12:50

因为运算符 ||&& 的返回类型与其左参数的类型不同。

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

您可以提出其他定义,例如 x ||= yif(!x) x = yx &&= y code> 为 if(!y) x = y,但这并不完全明显,也没有什么用处,因此未包含在内。

1在 C++ 中是 bool

Because the return type of operators || and && is not the same as type of their left argument.

The return type of || and && is always int1, while the left argument may be any integral, floating point or pointer type. The operands also don't have to be of the same type. Therefore defining x ||= y as x = x || y and x &&= y as x = x && y as would be consistent with other augmented assignments would not be able to store the result in the argument for most types.

You could come up with other definitions, e.g. x ||= y as if(!x) x = y and x &&= y as if(!y) x = y, but that would not be exactly obvious and it is not that useful, so it was not included.

1In C++ it is bool.

も让我眼熟你 2024-09-21 12:12:50

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

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

I guess the simple answer is that || is a boolean operator: and in C, a "boolean" is 0 or 1. The operands are implicitly converted to booleans (I have not checked that that's what the spec actually says, but it's how C behaves), and the result is a boolean.

Altering the semantics to support this pattern may well be feasible -- until someone relies on || doing what it's always done.

夜唯美灬不弃 2024-09-21 12:12:50

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

所以我能找到的唯一原因是,C89 中没有布尔类型,并且这些布尔运算符仅用于 if 中。

示例:

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; 实现为 if(!a) a = b; 会非常简单,并且已经被 Lua 等实现了。

所以你的问题似乎是,为什么 C 是这样设计的。
如果这个问题是关于 C++ 的,你可以问 Bjarne Stroustrup,问他发生了什么。由于事实并非如此,在我看来,这似乎是一种死胡同,因为该标准已经写了很久了,你不能再问人们,为什么要这么做。

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

我希望我能帮上一点忙。

I cannot find any particular reason, why the operators don't exist (in C99).

So the only reason I can find is, that there was no boolean type in C89, and those boolean operators were intended to be solely used in if's.

Example:

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 is now '1'', which for most people is pretty counter intuitive.

This operator obviously doesn't bring any clearence or coding improvement without the boolean type, that would make sence being or'd with another one.

In my opinion, the implementation of a ||= b; as if(!a) a = b; would be pretty straightforward and has aleardy been implemented by e.g. Lua.

So you're question seems to be a bit, why C has been designed the way it has been designed.
If this question was about C++, you could for example ask Bjarne Stroustrup and ask him, what had went into him. Since this is not the case, this seems to me to be kind of a dead end, because the standard has been written quite some time ago and you cannot really ask people anymore, why the h***.

On the other hand, this incomplete operator set should (in my opinion) aleardy have been made whole using a similar notation than yours, since in my opinion, there is no reason against it.

I hope I could help a little.

此生挚爱伱 2024-09-21 12:12:50

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

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

哪一个是结果||=compute(i)?它是模糊的,所以最好不要定义。

One simple explanation is this.

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

Which one would be result ||= compute(i)? It's ambiguous so it's better to not define.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文