Jon*_*ony 10 c++ operators bit-shift
如果移位运算符之后的值大于左侧操作数中的位数,则结果是未定义的.如果左侧操作数是无符号的,则右移是逻辑移位,因此高位将用零填充.如果左侧操作数已签名,则右移可能是也可能不是逻辑移位(即,行为未定义).
有人可以解释一下上面这些行是什么意思吗?
Ste*_*sop 23
这些线的意思并不重要,它们实质上是不正确的.
"如果移位运算符之后的值大于左侧操作数中的位数,则结果是未定义的."
是的,但应该说"大于或等于".5.8/1:
...如果右手操作数为负数,或者大于或等于提升左操作数的位长度,则行为未定义.
未定义的行为意味着"不要这样做"(见后文).也就是说,如果int您的系统是32位,那么您无法有效地执行以下任何操作:
int a = 0; // this is OK
a >> 32; // undefined behavior
a >> -1; // UB
a << 32; // UB
a = (0 << 32); // Either UB, or possibly an ill-formed program. I'm not sure.
Run Code Online (Sandbox Code Playgroud)
"如果左侧操作数是无符号的,则右移是一个逻辑移位,因此高位将用零填充."
这是真的.5.8/3说:
如果E1具有无符号类型或者E1具有有符号类型和非负值,则结果是E1的商除以提升到幂E2的数量2的积分部分
如果这对你更有意义.>>1与除以2相同,>>2除以4,>>3除以8,依此类推.在正值的二进制表示中,除以2与向右移动所有位,丢弃最小位,并用0填充最大位相同.
"如果左侧操作数已签名,则右移可能是也可能不是逻辑移位(即行为未定义)."
第一部分是正确的(它可能是也可能不是逻辑转变 - 它在某些编译器/平台上但不在其他编译器/平台上.我认为到目前为止最常见的行为是它不是).第二部分是假的,行为不是未定义的.未定义的行为意味着允许发生任何事情 - 崩溃,恶魔飞出你的鼻子,随机值,等等.标准不关心.有很多情况下C++标准说行为是未定义的,但这不是其中之一.
实际上,如果左手操作数是有符号的,并且值是正的,那么它的行为与无符号移位相同.
如果左侧操作数已签名,且值为负,则结果值是实现定义的.它不允许坠毁或着火.实现必须产生结果,并且实现的文档必须包含足够的信息来定义结果.实际上,"实现文档"从编译器文档开始,但这可能会隐式或显式地引用您的操作系统和/或CPU的其他文档.
再次从标准,5.8/3:
如果
E1已签名类型和负值,则结果值是实现定义的.
我假设你通过转移知道它意味着什么.假设您正在处理8位chars
unsigned char c;
c >> 9;
c >> 4;
signed char c;
c >> 4;
Run Code Online (Sandbox Code Playgroud)
第一个转换,编译器可以自由地做任何想做的事情,因为9> 8 [a中的位数char].未定义的行为意味着所有赌注都已关闭,无法知道将会发生什么.第二个转变很明确.你在左边得到0:11111111成为00001111.第三个转变与第一个转变一样,未定义.
注意,在第三种情况下,值c是什么并不重要.当它引用时signed,它表示变量的类型,而不是实际值是否大于零. signed char c = 5并且signed char c = -5都是签名的,向右移动是未定义的行为.
如果移位运算符之后的值大于左侧操作数中的位数,则结果是未定义的.
它意味着(unsigned int)x >> 33 可以做任何事情[1].
如果左侧操作数是无符号的,则右移是逻辑移位,因此高位将用零填充.
这意味着0xFFFFFFFFu >> 4必须0x0FFFFFFFu
如果左侧操作数已签名,则右移可能是也可能不是逻辑移位(即,行为未定义).
它意味着0xFFFFFFFF >> 4可以是0xFFFFFFFF(算术移位)或0x0FFFFFFF(逻辑移位)或任何物理定律允许的,即结果是不确定的.
[1]:在具有32位的32位机器上int.
| 归档时间: |
|
| 查看次数: |
16973 次 |
| 最近记录: |