我目前正试图了解这种逻辑转变是如何运作的。 给定公式:
int logicalShift(int x, int n){
int mask = x >> 31 << 31 >> n << 1;
return mask^ (x>>n);
}
x = 0x87654321 and n = 4.
的试运行给了logicalShift(x,n) = 0x08765432
在这里,我知道二进制中的x是1000 0111 0110 0101 0100 0011 0010 0001
并且遵循掩码过程
x&gt;&gt; 31是0000 0000 0000 0000 0000 0000 0000 0001
和&lt;&lt; 31到那是1000 0000 0000 0000 0000 0000 0000 0000
和&gt;&gt;那是0000 1000 0000 0000 0000 0000 0000 0000
和&lt;&lt; 1到那是0001 0000 0000 0000 0000 0000 0000 0000
。
执行mask^ (x>>n)
表示使用0001 0000 0000 0000 0000 0000 0000 0000
对0000 1000 0111 0110 0101 0100 0011 0010
执行XOR,结果为0001 1000 0111 0110 0101 0100 0011 0010
,即0x18765432。
我做错了吗?
答案 0 :(得分:2)
这段摘录错了:
int logicalShift(int x, int n){
int mask = x >> 31 << 31 >> n << 1;
return mask^ (x>>n);
}
x >> 31
为负时x
的行为是实现定义的。带有负值的<< 31
或更改符号位的int
具有未定义的行为。它会像在非常严格的假设下进行逻辑转换一样工作:
int
的宽度为32位这不符合C标准。但是,它会在unsigned
为32位宽的任何GCC目标平台上按预期运行,因为GCC将最后3个指定为真。
此代码错误,因为要进行正确的逻辑移位,应使用n
值。但是,要将这些返回转换为有符号的值是很棘手的 - 而不是通常需要它。
此函数已完全定义逻辑右移的行为,因为x
的值在限制范围内(非负数且小于unsigned int logicalShift(unsigned int x, int n) {
return x >> n;
}
的宽度(以位为单位)):
saveClientToDatabase
由于它只做一个表达式,我们注意到不需要使用函数进行这样的操作。
答案 1 :(得分:1)
是的,你做错了。当>>
的左操作数是有符号整数时,编译器通常会执行算术右移,而不是逻辑右移。这在函数名称中暗示:如果>>
执行了逻辑右移,它可以直接返回x >> n
。该函数的要点是通过使用算术右移来实现逻辑右移。
什么算术右移意味着当右移时,左边的位没有用零填充,而是用最左边的位(符号位)填充。因此:
x&gt;&gt; 31是
0000 0000 0000 0000 0000 0000 0000 0001
x&gt;&gt; 31实际上是1111 1111 1111 1111 1111 1111 1111 1111
。
答案 2 :(得分:0)
x >> 31 is 0000 0000 0000 0000 0000 0000 0000 0001
不,错了。您的x
为signed
整数且num
为0x87654321
,表示最后31st bit
为1 or set
,因此当您正确移位时sign
位被复制,结果x
为1111 1111 1111 1111 1111 1111 1111 1111
要获得预期输出,请将num
设为unsigned
类型。
int logicalShift(unsigned int x, int n){
/* some code */
}
请注意,其实现依赖于如果您的处理器支持算术右移,那么last bit(sign bit)
会被复制到剩余的字节中,如果它的逻辑右移,那么它就不会。