我有以下示例代码:按位变速操作uint64_t中可变
uint64_t x, y;
x = ~(0xF<<24);
y = ~(0xFF<<24);
其结果将是:
x=0xfffffffff0ffffff
y=0xfffff
任何人都可以解释不同?为什么x在64位上计算,而y只在32上计算?
我有以下示例代码:按位变速操作uint64_t中可变
uint64_t x, y;
x = ~(0xF<<24);
y = ~(0xFF<<24);
其结果将是:
x=0xfffffffff0ffffff
y=0xfffff
任何人都可以解释不同?为什么x在64位上计算,而y只在32上计算?
默认操作是32位。
x=~(0xf<<24);
这个代码可以分解为以下步骤:
int32_t a;
a=0x0000000f;
a<<=24; // a=0x0f000000;
a=~a; // a=0xf0ffffff;
x=(uint64_t)a; // x = 0xfffffffff0ffffff;
而且,
y = ~(0xFF<<24);
int32_t a;
a=0x000000ff;
a<<=24; // a=0xff000000;
a=~a; // a=0x00ffffff;
x=(uint64_t)a; // x = 0x000000000ffffff;
0x0f << 24
由于是作为int
观察时的正数,它是符号扩展到一个正数,即,0x00000000_0f000000
(下划线是只是为了可读性,C不支持此语法)。然后这转变成你所看到的。
0xff << 24
另一方面是否定的,所以它的符号扩展是不同的。
严格来说,32位系统的0xFF << 24是未定义的行为,其结果可能是任何东西。 – Lundin 2012-02-15 10:52:15
你已经在你的程序中没有定义,所以任何可能发生的事情。
int
,相当于signed int
。在这个特定的平台上,int
显然是32位。int
。int
因此不会发生隐式类型提升。因此,< <操作的结果也是(签名)int
。int
,所以一切正常。int
!在这里,未定义的行为被调用,任何事情都可能发生。ISO 9899:2011 6.5.7/4:
“E1的结果< < E2是E1左移E2的位位置;腾空 比特以零填充”/-/
“如果E1有一个签名的类型和非负的值,E1×2E2是结果类型表示的, 然后就是所得到的值;否则,该行为是 未定义。
因此不能使用表达式0xFF < < 24。此后该程序可以自由打印任何垃圾值。
但是,如果我们忽略了一个专注于为0x0F < 24:
int
。 〜运算符应用于此。蝽象这是为什么编码标准MISRA-C包含一个禁止在表达式中使用整数文字的规则数量。符合MISRA-C的代码必须在每个整数文字(MISRA-C:2004 10.6)之后使用u
后缀,并且该代码不允许对有符号整数执行按位运算(MISRA-C:2004 12.7)。
其他海报显示了它为什么这样做。但要获得预期的结果:
uint64_t x, y;
x = ~(0xFULL<<24);
y = ~(0xFFULL<<24);
或者你也可以做到这一点(我不知道这是不是比上述任何较慢虽然):
uint64_t x, y;
x = ~(uint64_t(0xF)<<24);
y = ~(uint64_t(0xFF)<<24);
然后:
x = 0xfffffffff0ffffff
y = 0xffffffff00ffffff
要挑剔,默认值是(有符号)'int',不管它是什么。 – Lundin 2012-02-15 09:57:52
严格来说,32位系统的0xFF << 24是未定义的行为,其结果可能是任何东西。 – Lundin 2012-02-15 10:52:29
我不能同意。行为应该是可预测的。如果'a'的类型是'char',那么0xff << 24将产生负值;否则,如果'a'的类型为short或int,则它将是一个正值。 – ciphor 2012-02-15 12:29:35