C++ 中的移位运算符
如果移位运算符后的值 大于位数 左边的操作数,结果是 不明确的。如果左侧操作数是 无符号,右移是逻辑 移位,以便填充高位 带零。如果左侧操作数 是有符号的,右移可能或可能 不是逻辑移位(即 行为未定义)。
有人可以解释一下上面几行的意思吗?
If the value after the shift operator
is greater than the number of bits in
the left-hand operand, the result is
undefined. If the left-hand operand is
unsigned, the right shift is a logical
shift so the upper bits will be filled
with zeros. If the left-hand operand
is signed, the right shift may or may
not be a logical shift (that is, the
behavior is undefined).
Can somebody explain me what the above lines mean??
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这些行的含义并不重要,它们基本上是不正确的。
“如果移位运算符后的值
大于位数
左边的操作数,结果是
未定义。”
是正确的,但应该说“大于或等于”。5.8/1:
未定义的行为意味着“不要这样做”(见下文)。也就是说,如果
int
在您的系统上是 32 位,那么您将无法有效地执行以下任何操作:“如果左侧操作数是无符号的,则右移是逻辑操作数移位,因此高位将用零填充。”
这是真的。 5.8/3 说:
如果这对您来说更有意义)。
>>1
与除以 2 相同,>>2
除以 4,>>3
除以 8 , 等等。在正值的二进制表示中,除以 2 与将所有位向右移动 1、丢弃最小位并用 0 填充最大位相同。"如果左侧操作数是有符号,右移可能是也可能不是逻辑移位(即行为未定义)。”
第一部分是正确的(它可能是也可能不是逻辑移位 - 它在某些编译器/平台上但我认为到目前为止最常见的行为不是)。第二部分是假的,行为不是未定义的。未定义的行为意味着任何事情都可以发生 - 碰撞、恶魔从你的鼻子里飞出来、随机值等等。标准不在乎。在很多情况下,C++ 标准表示行为未定义,但这不是其中之一。
事实上,如果左侧操作数有符号且值为正,则其行为与无符号移位相同。
如果左侧操作数有符号且值为负,则结果值是实现定义的。不允许坠毁或着火。实现必须产生结果,并且实现的文档必须包含足够的信息来定义结果。实际上,“实现文档”从编译器文档开始,但这可能会隐式或显式地将您引向操作系统和/或 CPU 的其他文档。
再次来自标准 5.8/3:
It doesn't matter too much what those lines mean, they are substantially incorrect.
"If the value after the shift operator
is greater than the number of bits in
the left-hand operand, the result is
undefined."
Is true, but should say "greater than or equal to". 5.8/1:
Undefined behavior means "don't do it" (see later). That is, if
int
is 32 bits on your system, then you can't validly do any of the following:"If the left-hand operand is unsigned, the right shift is a logical shift so the upper bits will be filled with zeros."
This is true. 5.8/3 says:
if that makes any more sense to you.
>>1
is the same as dividing by 2,>>2
dividing by 4,>>3
by 8, and so on. In a binary representation of a positive value, dividing by 2 is the same as moving all the bits one to the right, discarding the smallest bit, and filling in the largest bit with 0."If the left-hand operand is signed, the right shift may or may not be a logical shift (that is, the behavior is undefined)."
First part is true (it may or may not be a logical shift - it is on some compilers/platforms but not others. I think by far the most common behaviour is that it is not). Second part is false, the behavior is not undefined. Undefined behavior means that anything is permitted to happen - a crash, demons flying out of your nose, a random value, whatever. The standard doesn't care. There are plenty of cases where the C++ standard says behavior is undefined, but this is not one of them.
In fact, if the left hand operand is signed, and the value is positive, then it behaves the same as an unsigned shift.
If the left hand operand is signed, and the value is negative, then the resulting value is implementation-defined. It isn't allowed to crash or catch fire. The implementation must produce a result, and the documentation for the implementation must contain enough information to define what the result will be. In practice, the "documentation for the implementation" starts with the compiler documentation, but that might refer you implicitly or explicitly to other docs for the OS and/or the CPU.
Again from the standard, 5.8/3:
我假设您知道转移意味着什么。假设您正在处理一个 8 位 char
第一次转变,编译器可以自由地做任何它想做的事情,因为 9 > 。 8 [
char
中的位数]。未定义的行为意味着所有的赌注都失败了,无法知道会发生什么。第二个转变是明确的。左侧有 0:11111111
变为00001111
。与第一个转变一样,第三个转变也是未定义的。请注意,在第三种情况下,
c
的值是什么并不重要。当它引用signed
时,它表示变量的类型,而不是实际值是否大于零。signed char c = 5
和signed char c = -5
都是有符号的,向右移位是未定义的行为。I'm assuming you know what it means by shifting. Lets say you're dealing with a 8-bit
char
sThe first shift, the compiler is free to do whatever it wants, because 9 > 8 [the number of bits in a
char
]. Undefined behavior means all bets are off, there is no way of knowing what will happen. The second shift is well defined. You get 0s on the left:11111111
becomes00001111
. The third shift is, like the first, undefined.Note that, in this third case, it doesn't matter what the value of
c
is. When it refers tosigned
, it means the type of the variable, not whether or not the actual value is greater than zero.signed char c = 5
andsigned char c = -5
are both signed, and shifting to the right is undefined behavior.这意味着
(unsigned int)x >>> 33
可以做任何事情 [1]。这意味着
0xFFFFFFFFu >>> 4
必须是0x0FFFFFFu
这意味着
0xFFFFFFFF >> 4
可以是0xFFFFFFFF
(算术移位)或0x0FFFFFFF
(逻辑移位)或物理定律允许的任何内容,即结果未定义。[1]:在具有 32 位
int
的 32 位机器上。It means
(unsigned int)x >> 33
can do anything[1].It means
0xFFFFFFFFu >> 4
must be0x0FFFFFFFu
It means
0xFFFFFFFF >> 4
can be0xFFFFFFFF
(arithmetic shift) or0x0FFFFFFF
(logical shift) or anything-allowed-by-physical-law, i.e. the result is undefined.[1]: on 32-bit machine with a 32-bit
int
.如果尝试将 32 位整数移位 33,则结果是未定义的。即,它可能全为零,也可能不全零。
无符号数据类型右移时将用零填充。
所以
1100>> 1==0110
如果数据类型是有符号的,则行为未定义。有符号数据类型以特殊格式存储,其中最左边的位表示正或负。因此,对有符号整数进行移位可能不会达到您的预期。有关详细信息,请参阅维基百科文章。
http://en.wikipedia.org/wiki/Logical_shift
If you try to shift a 32-bit integer by 33 the result is undefined. i.e., It may or may not be all zeros.
Unsigned data type will be padded with zeros when right shifting.
so
1100 >> 1 == 0110
If the data type is signed, the behavior is not defined. Signed data types are stored in a special format, where the left most bit indicates positive or negative. So shifting on a signed integer may not do what you expect. See the Wikipedia article for details.
http://en.wikipedia.org/wiki/Logical_shift
为了提供一些背景信息,这是该段落的开头:
现在剩下的,有解释:
如果您有一个 32 位整数,并且尝试位移 33 位,则这是不允许的,并且结果是未定义的。换句话说,结果可能是任何结果,否则你的程序可能会崩溃。
这表示它被定义为编写
a >> b
当 a 是无符号整数时。当右移时,最低有效位被删除,其他位向下移动,最高有效位变为零。换句话说:
实际上,我相信这里的行为是当
a
为负数时定义的实现,以及当a
为正数时定义的行为,而不是引用中建议的未定义。这意味着如果您执行a >> b
当a
是负整数时,可能会发生许多不同的情况。要查看您获得的结果,您应该阅读编译器的文档。常见的实现是,如果数字为正,则移入 0;如果数字为负,则移入 1,但如果您希望编写可移植代码,则不应依赖此行为。To give some context, here's the start of that paragraph:
Now the rest, with explanations:
If you have a 32 bit integer and you try to bit shift 33 bits, that's not allowed and the result is undefined. In other words, the result could be anything, or your program could crash.
This says that it's defined to write
a >> b
when a is an unsigned int. As you shift right, the least significant bits are removed, other bits are shifted down, and the most significant bits become zero.In other words:
Actually I believe that the behaviour here is implementation defined when
a
is negative and defined whena
is positive rather than undefined as suggested in the quote. This means that if you doa >> b
whena
is a negative integer, there are many different things that might happen. To see which you get, you should read the documentation for your compiler. A common implementation is to shift in zeros if the number is positive, and ones if the number is negative, but you shouldn't rely on this behaviour if you wish to write portable code.我认为关键词是“未定义”,这意味着规范没有说明应该发生什么。大多数编译器在这种情况下会做一些明智的事情,但通常不能依赖于任何行为。通常最好避免调用未定义的行为,除非您使用的编译器的文档说明了它在特定情况下的作用。
第一句话表示,如果您尝试将 32 位值移位超过 32 位,则它是未定义的。
第二个表示,如果将无符号整数右移,左侧的位将被零填充。
第三个表示,如果将有符号 int 右移,则未定义将放入左手位的内容。
I suppose the key word is "undefined", which means that the specification does not say what should happen. Most compilers will do something sensible in such cases, but you cannot depend on any behaviour generally. It is usually best to avoid invoking undefined behavior unless the documentation for the compiler you are using states what it does in the specific case.
The first sentence says it's undefined if you try to shift, for example, a 32 bit value by more than 32 bits.
The second says that if you shift an unsigned int right, the left hand bits will get filled with zeros.
The third says that if you shift a signed int right, it is not defined what will be put in the left hand bits.