【发布时间】:2012-10-04 22:00:42
【问题描述】:
在 C 语言中,在 32 位机器上,我只是想知道 1>>31 是否返回 -1 给定 1 是有符号整数,因为对于 2 的补码,在进行右移(算术)时,符号位被复制给出结果
1111 1111 1111 1111 1111 1111 1111 1111
【问题讨论】:
标签: c bit-manipulation bit-shift
在 C 语言中,在 32 位机器上,我只是想知道 1>>31 是否返回 -1 给定 1 是有符号整数,因为对于 2 的补码,在进行右移(算术)时,符号位被复制给出结果
1111 1111 1111 1111 1111 1111 1111 1111
【问题讨论】:
标签: c bit-manipulation bit-shift
不,在任何符合要求的实现中,结果都将为零。
C99, 6.5.7/5(“按位移位运算符”)状态:
E1 >> E2 的结果是 E1 右移 E2 位位置。如果 E1 有 一个无符号类型,或者如果 E1 有一个有符号类型和一个非负值, 结果的值是 E1 / 商的整数部分 2^E2。如果 E1 有带符号类型和负值,则结果值 是实现定义的。
由于1 是非负数,因此结果是1 / (2^31) 的积分商,显然为零。
【讨论】:
1的符号位是0...不是吗?即使它是一个负数,结果也是“实现定义的”,如答案主体中 C 标准的引用中所述。
结果将为零,因为整数 1 的符号位(最高有效位)为 0:
0000 0000 0000 0000 0000 0000 0000 0001
^
【讨论】:
1>>31 的结果为零,因为 1 的符号位为 0。
但是,您不能指望被复制的符号位,因为根据 K&R 第二版,结果是针对有符号值的右移实现定义的。
【讨论】:
对于使用二进制补码表示ints 的实现,以下代码有助于确定右移是否是有符号整数的算术运算。
#include <stdio.h>
//below function returns 1 if system is little endian, 0 otherwise
int is_little_endian() { //checks endianness
short x = 0x0100; //256
char *p = (char*) &x;
if (p[0] == 0) {
return 1;
}
return 0;
}
/* Below function returns 1 if shifts are arithmetic, 0 otherwise.
It checks whether the most significant bit is 1 or 0, for an int which
had most the significant bit as 1 prior to the right shift. If the MSB
is 1 after the bit shift, then the (unsigned) value of the most
significant Byte would be 255.
*/
int int_shifts_are_arithmetic() {
int x = -2;
x = x >> 1 ;
char *px = (char*)&x;
if (is_little_endian()) {
unsigned char *upx = (unsigned char*)&px[(int)sizeof(int) - 1];
if (upx[0] == 255) return 1;
return 0;
} else { //big endian
unsigned char* upx = (unsigned char*)px;
if (upx[0] == 255) return 1;
return 0;
}
}
int main() {
if (int_shifts_are_arithmetic()) {
printf("Shifts are arithmetic\n");
}
else {
printf("Shifts are not arithmetic\n");
}
return 0;
}
【讨论】: