数字1,右移任何大于0的位数,结果应该是0,对吗?但我可以输入这个非常简单的程序打印出1。
#include <stdio.h>
int main()
{
int b = 0x80000000;
int a = 1 >> b;
printf("%d\n", a);
}
在 Linux 上使用 gcc 进行测试。
数字1,右移任何大于0的位数,结果应该是0,对吗?但我可以输入这个非常简单的程序打印出1。
#include <stdio.h>
int main()
{
int b = 0x80000000;
int a = 1 >> b;
printf("%d\n", a);
}
在 Linux 上使用 gcc 进行测试。
6.5.7 位移运算符:
如果右操作数的值为负数或大于等于提升后的左操作数宽度,则行为未定义。
编译器可以做任何事情,但最常见的行为是完全优化表达式(以及依赖它的任何东西)或仅让底层硬件执行超出范围的移位。许多硬件平台(包括x86和ARM)掩盖一些低阶位用作移位量。实际的硬件指令将返回在这些平台上观察到的结果,因为移位量被掩盖为零。因此,在您的情况下,编译器可能已经优化了移位,或者只是让硬件执行其本身的操作。如果您想知道哪个,请检查汇编代码。
not
几乎肯定会和位移一样快,如果不是更快。 - BlueRaja - Danny Pflughoeft~foo
,它是按位取反。或者,如果你想在0和1之间切换,你可以使用foo^1
。显然,这两种方法都只是在0和特定的另一个值之间切换。 - fluffy很可能它并没有试图通过一些大量的位移来进行转换。
在您的系统上,INT_MAX
很可能是 2**31-1 或者 0x7fffffff(我使用 **
表示指数)。如果是这种情况,在声明中:
int b = 0x80000000;
(在问题中缺少一个分号,请复制并粘贴您的确切代码) 常量0x80000000
是unsigned int
类型,而不是int
。该值被隐式转换为int
。由于结果超出了int
的限制,因此结果是实现定义的(或者在C99中可能会引发实现定义的信号,但我不知道任何实现这样做)。
这种情况下最常见的方法是将无符号值的位重新解释为2的补码有符号值。在这种情况下,结果是-2 ** 31
,或-2147483648
。
因此,行为不是未定义的,因为您正在移位等于或超过int
类型的宽度的值,而是未定义的,因为您正在移位(非常大的)负数值。
当然,这并不重要;未定义就是未定义。
注意:上述假设您的系统中的int为32位。如果int比32位更宽,则大部分内容不适用(但行为仍未定义)。unsigned long b = 0x80000000;
unsigned long a = 1 >> b; // *still* undefined
unsigned long
被保证足够大以容纳值0x80000000
,因此您避免了问题的一部分。
当然,移位的行为与原始代码中一样未定义,因为0x80000000
大于或等于unsigned long
的宽度。 (除非您的编译器具有非常大的unsigned long
类型,但实际上没有任何现实世界的编译器这样做。)
避免未定义行为的唯一方法是不要做您正在尝试做的事情。
原始代码的行为可能,但几乎不可能不是未定义的。这只有在从unsigned int
到int
的实现定义转换产生介于0和31之间的值时才会发生。如果int
小于32位,则转换很可能产生0。
int
的系统上,这种情况是相当可能的,而这种系统也并非闻所未闻。 - caf阅读一下,或许能帮到你:
expression1 >> expression2
>> 运算符掩盖 expression2,以避免将 expression1 左移太多。这是因为如果移位量超过了 expression1 数据类型中的位数,所有原始位都将被移走,得到一个微不足道的结果。
现在为了确保每次移位至少留下一个原始位,移位运算符使用以下公式来计算实际移位量:
使用按位与运算符将 expression2 掩码(mask)为 expression1 中位数减一。
例如:
var x : byte = 15;
// A byte stores 8 bits.
// The bits stored in x are 00001111
var y : byte = x >> 10;
// Actual shift is 10 & (8-1) = 2
// The bits stored in y are 00000011
// The value of y is 3
print(y); // Prints 3
"8-1"是因为x是8个字节,所以操作将使用7位。那个void函数会删除原始链的最后一位。
gcc
完全尊重 UB 的精神,根据条件提供不同的“错误”结果(http://gcc.gnu.org/ml/gcc/2004-11/msg01131.html)。 - Matteo Italia