为什么C没有逻辑赋值运算符?
我需要编写一个如下形式的语句
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
返回整数值,首先是 a
和 expr
将隐式转换为“布尔值”,然后将“布尔值”分配给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 toa
, and return it
The steps above seem to be the same for both the assignment and normal case.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
a ||= expr
由于对其等价a = a || 的短路求值而存在问题。表达式
。拥有像
a = a || 这样的
考虑OP的断言:a ||= expr
函数expr这不太正确。如果
a
计算结果为true
,则expr
将不会被转换。如果expr
是scanf()
或rand()
或某些影响程序状态的函数,这将会产生影响。a ||= scanf("%d", &i) != 1;
等代码只会尝试扫描a
中包含错误值的数据。尽管可以通过这种方式扩展语言,但对当前的||
和&&
组添加额外的短路运算符可能会导致更多的编码问题明显的简化。另一方面:一种快速但令人困惑的编写代码的方法,其中函数在出错时返回非零代码。
a ||= expr
is problematic due to short circuit evaluation of its equivalenta = a || expr
.To have
a ||= expr
function likea = a || expr
consider OP's assertion:This is not quite correct.
expr
will not be converted ifa
evaluates totrue
. This would make a difference shouldexpr
be something likescanf()
orrand()
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 ina
. 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.
因为运算符
||
和&&
的返回类型与其左参数的类型不同。||
和&&
的返回类型始终为int
1,而左侧参数可以是任何整型、浮点型或指针类型。操作数也不必是同一类型。因此将x ||= y
定义为x = x || y
和x &&= y
为x = x && y
与其他增强赋值一致,无法将结果存储在大多数类型的参数中。您可以提出其他定义,例如
x ||= y
为if(!x) x = y
和x &&= 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 alwaysint
1, 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 definingx ||= y
asx = x || y
andx &&= y
asx = 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
asif(!x) x = y
andx &&= y
asif(!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
.我想简单的答案是
||
是一个布尔运算符:在 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.我找不到任何特定原因,为什么运算符不存在(在 C99 中)。
所以我能找到的唯一原因是,C89 中没有布尔类型,并且这些布尔运算符仅用于
if
中。示例:
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:
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;
asif(!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.
一个简单的解释是这样的。
哪一个是
结果||=compute(i)
?它是模糊的,所以最好不要定义。One simple explanation is this.
Which one would be
result ||= compute(i)
? It's ambiguous so it's better to not define.