[英]could logical negation have been implemented as bitwise negation in legacy compilers?
I just found legacy code which tests a flag like this: 我刚刚发现遗留代码测试这样的标志:
if( some_state & SOME_FLAG )
So far, so good! 到现在为止还挺好!
But further in code, I see an improper negation 但是在代码中,我看到了一个不正当的否定
if( ! some_state & SOME_FLAG )
My understanding is that it is interpreted as (! some_state) & SOME_FLAG
which is probably a bug, and gcc logically barks with -Wlogical-not-parentheses
... 我的理解是它被解释为(! some_state) & SOME_FLAG
这可能是一个bug,而gcc在逻辑上咆哮着-Wlogical-not-parentheses
...
Though it could eventually have worked in the past if ever !some_state
was implemented as ~some_state
by some legacy compiler. 虽然它最终可能在过去有效!some_state
被一些遗留编译器实现为~some_state
。 Does anyone know if it was possibly the case? 有谁知道是否可能如此?
EDIT 编辑
sme_state
is declared as int (presumably 32 bits, 2 complement on target achitecture). sme_state
声明为int(可能是32位,目标sme_state
上的2个补码)。
SOME_FLAG
is a constant set to a single bit 0x00040000, so SOME_FLAG & 1 == 0
SOME_FLAG
是一个常量设置为单个位0x00040000,因此SOME_FLAG & 1 == 0
Logical negation and bitwise negation have never been equivalent. 逻辑否定和按位否定从来都不相同。 No conforming compiler could have implemented one as the other. 没有符合标准的编译器可以实现另一个。 For example, the bitwise negation of 1 is not 0, so ~1 != !1
. 例如,1的按位取反不是0,所以~1 != !1
。
It is true that the expression ! some_state & SOME_FLAG
表达确实如此! some_state & SOME_FLAG
! some_state & SOME_FLAG
is equivalent to (! some_state) & SOME_FLAG
because logical negation has higher precedence than bitwise and. ! some_state & SOME_FLAG
相当于(! some_state) & SOME_FLAG
因为逻辑否定的优先级高于bitwise和。 That is indeed suspicious , but the original code is not necessarily in error. 这确实是可疑的 ,但原始代码不一定是错误的。 In any case, it is more likely that the program is buggy in this regard than that any C implementation evaluated the original expression differently than the current standard requires, even prior to standardization. 在任何情况下,在这方面,程序更有可能是错误的,因为任何C实现都会以不同于当前标准的要求评估原始表达式,甚至在标准化之前。
Since the expressions (! some_state) & SOME_FLAG
and !(some_state & SOME_FLAG)
will sometimes evaluate to the same value -- especially if SOME_FLAG
happens to expand to 1
-- it is also possible that even though they are inequivalent, their differences do not manifest during actual execution of the program. 由于表达式(! some_state) & SOME_FLAG
和!(some_state & SOME_FLAG)
有时会评估为相同的值 - 特别是如果SOME_FLAG
恰好扩展为1
- 也有可能即使它们不相等,它们的差异也不会在实际执行程序期间显示。
While there was no standard before 1989, and thus compilers could do things as they wished, no compiler to my knowledge has ever done this; 虽然1989年之前没有标准,因此编译器可以按照自己的意愿做事,但据我所知,没有任何编译器可以做到这一点; changing the meaning of operators wouldn't be a smart call if you want people to use your compiler. 如果您希望人们使用您的编译器,更改运算符的含义将不是一个聪明的调用。
There's very little reason to write an expression like (!foo & FLAG_BAR)
; 写一个像(!foo & FLAG_BAR)
这样的表达式的理由很少; the result is just !foo
if FLAG_BAR
is odd or always zero if it is even. 结果只是!foo
如果FLAG_BAR
是奇数,或者如果是偶数则总是为零。 What you've found is almost certainly just a bug. 你发现的几乎肯定只是一个bug。
It would not be possible for a legacy compiler to implement !
遗留编译器无法实现!
as bitwise negation, because such approach would produce incorrect results in situations when the value being negated is outside the {0, 0xFF...FF} set. 作为按位否定,因为当被否定的值超出{0,0xFF ... FF}集时,这种方法会产生不正确的结果。
Standard requires the result of !x
to produce zero for any non-zero value of x
. 标准要求的结果!x
产生零对任何非零值x
。 Hence, applying !
因此,申请!
to, say, 1 would yield 0xFF..FFFE, which is non-zero. 比方说,1会产生0xFF..FFFE,这是非零的。
The only situation when the legacy code would have worked as intended is when SOME_FLAG
is set to 1
. 遗留代码按预期工作的唯一情况是SOME_FLAG
设置为1
。
Let's start with the most interesting (and least obvious) part: gcc logically barks with -Wlogical-not-parentheses
. 让我们从最有趣(也是最不明显)的部分开始:gcc逻辑上用-Wlogical-not-parentheses
咆哮。 What does this mean? 这是什么意思?
C has two different operators that have similar looking characters (but different behaviour and intended for very different purposes) - the &
which is a bitwise AND, and &&
which is a boolean AND. C有两个不同的运算符,它们具有相似的外观字符(但行为不同,用于非常不同的目的) - &
是一个按位AND,而&&
是一个布尔AND。 Unfortunately this led to typos, in the same way that typing =
when you meant ==
can cause problems, so some compilers (GCC) decided to warn people about " &
without parenthesis used as a condition" (even though it's perfectly legal) to reduce the risk of typos. 不幸的是,这导致了拼写错误,就像打字=
当你的意思==
会导致问题时,所以一些编制者(GCC)决定警告人们“ &
没有括号作为条件”(即使它是完全合法的)减少错别字的风险。
Now... 现在...
You're showing code that uses &
(and not showing code that uses &&
). 您正在显示使用&
代码(并且不显示使用&&
代码)。 This implies that some_state
is not a boolean and is number. 这意味着some_state
不是布尔值而且是数字。 More specifically it implies that each bit in some_state
may be completely independent and unrelated. 更具体地说,它意味着some_state
中的每个位可以完全独立some_state
相关。
For an example of this, let's pretend that we're implementing a Pacman game and need a nice compact way to store the map for each level. 举个例子,让我们假装我们正在实施一个Pacman游戏,需要一个很好的紧凑方式来存储每个级别的地图。 We decide that each tile in the map might be a wall or not, might be a collected dot or not, might be power pill or not, and might be a cherry or not. 我们认为地图中的每个瓷砖可能都是墙,可能是一个收集的点,也可能不是,但可能是一个或不是樱桃。 Someone suggests that this can be an array of bytes, like this (assuming the map is 30 tiles wide and 20 tiles high): 有人建议这可以是一个字节数组,就像这样(假设地图是30个瓷砖宽,20个瓷砖高):
#define IS_WALL 0x01
#define HAS_DOT 0x02
#define HAS_POWER_PILL 0x04
#define HAS_CHERRY 0x08
uint8_t level1_map[20][30] = { ..... };
If we want to know if a tile happens to be safe to move into (no wall) we could do this: 如果我们想知道瓷砖是否安全进入(无墙)我们可以这样做:
if( level1_map[y][x] & IS_WALL == 0) {
For the opposite, if we want to know if a tile is a wall we could do any of these: 相反,如果我们想知道瓷砖是否是墙,我们可以做以下任何一种:
if( level1_map[y][x] & IS_WALL != 0) {
if( !level1_map[y][x] & IS_WALL == 0) {
if( level1_map[y][x] & IS_WALL == IS_WALL) {
..because it makes no difference which one it is. 因为它与哪一个没什么区别。
Of course (to avoid the risk of typos) GCC might (or might not) warn about some of these. 当然(为了避免拼写错误的风险)GCC可能(或可能不会)警告其中一些。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.