简体   繁体   English

uint64_t变量中C的按位移位运算

[英]Bitwise shift operation in C on uint64_t variable

I have the following sample code: 我有以下示例代码:

uint64_t x, y;
x = ~(0xF<<24);
y = ~(0xFF<<24);

The result would be: 结果将是:

x=0xfffffffff0ffffff
y=0xfffff

Can anyone explain the difference? 有人可以解释这个区别吗? Why x is calculated over 64 bit and y only on 32? 为什么x计算超过64位而y只计算在32位?

The default operation is 32 bit. 默认操作是32位。

x=~(0xf<<24);

This code could be disassembled into the following steps: 此代码可以反汇编为以下步骤:

int32_t a;
a=0x0000000f;
a<<=24;   // a=0x0f000000;
a=~a;     // a=0xf0ffffff;
x=(uint64_t)a;  // x = 0xfffffffff0ffffff;

And, 和,

y = ~(0xFF<<24);

int32_t a;
a=0x000000ff;
a<<=24;   // a=0xff000000;
a=~a;     // a=0x00ffffff;
x=(uint64_t)a;  // x = 0x000000000ffffff;

Because 0x0f << 24 is a positive number when viewed as an int , it's sign-extended to a positive number, ie to 0x00000000_0f000000 (the underscore is just for readability, C does not support this syntax). 因为0x0f << 24在被视为int时是正数,所以它被符号扩展为正数,即到0x00000000_0f000000 (下划线只是为了可读性,C不支持这种语法)。 This is then inverted into what you're seeing. 然后将其转换为您所看到的内容。

0xff << 24 on the other hand is negative, so it's sign-extended differently. 另一方面, 0xff << 24是负数,因此它的符号扩展方式不同。

Other posters have shown why it does this. 其他海报已经说明了为什么会这样做。 But to get the expected results: 但要获得预期的结果:

uint64_t x, y; 
x = ~(0xFULL<<24); 
y = ~(0xFFULL<<24);

Or you can do this (I don't know if this is is any slower than the above though): 或者你可以这样做(我不知道这是否比上面的慢):

uint64_t x, y; 
x = ~(uint64_t(0xF)<<24); 
y = ~(uint64_t(0xFF)<<24); 

Then: 然后:

x = 0xfffffffff0ffffff
y = 0xffffffff00ffffff

You have undefined behavior in your program so anything might happen. 您的程序中有未定义的行为,因此可能发生任何事情。

  • The integer literals 0xF or 0xFF are of type int , which is equivalent to signed int . 整数文字0xF或0xFF的类型为int ,相当于signed int On this particular platform, int is apparently 32 bits. 在这个特定的平台上, int显然是32位。
  • The integer literal 24 is also a (signed) int . 整数文字24也是(带符号) int
  • When the compiler evaluates the << operation, both operands are (signed) int so no implicit type promotions take place. 当编译器评估<< operation时,两个操作数都是(signed) int因此不会发生隐式类型的提升。 The result of the << operation is therefore also a (signed) int . 因此<<操作的结果也是(签名的) int
  • The value 0xF<<24 = 0x0F000000 fits in a (signed) int as a non-negative value, so everything is ok. 值0xF << 24 = 0x0F000000作为非负值适合(带符号) int ,因此一切正常。
  • The value 0xFF<<24 = 0xFF000000 does not fit in (signed) int ! 值0xFF << 24 = 0xFF000000 不适合 (signed) int Here, undefined behavior is invoked and anything might happen. 在这里,调用未定义的行为,并且可能发生任何事情。

ISO 9899:2011 6.5.7/4: ISO 9899:2011 6.5.7 / 4:

"The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros." “E1 << E2的结果是E1左移E2位位置;空位用零填充。” /--/ / - /

"If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined. “如果E1具有带符号类型和非负值,并且E1×2E2在结果类型中可表示,那么这就是结果值;否则,行为是未定义的。

So the expression 0xFF<<24 can't be used. 因此不能使用表达式0xFF << 24。 The program is free to print any garbage value after that. 该程序可以随后打印任何垃圾值。

But if we ignore that one and focus on 0x0F<24: 但如果我们忽略那一个并专注于0x0F <24:

  • 0x0F000000 is still a (signed) int . 0x0F000000仍然是(签名) int The ~operator is applied to this. 〜运算符适用于此。
  • The result is 0xF0FFFFFF, which is still a signed int. 结果是0xF0FFFFFF,它仍然是一个signed int。 And on almost any system, this 32-bit hex equals a negative number in two's complement. 几乎在任何系统上,这个32位十六进制等于二进制补码中的负数。
  • This signed int is converted to the type uint64_t during assignment. 在赋值期间,此signed int将转换为uint64_t类型。 This is done in two steps, first by converting it to a signed 64 bit, then by converting that signed 64 to an unsigned 64. 这分两步完成,首先将其转换为带符号的64位,然后将带符号的64转换为无符号64。

Bugs like this is why the coding standard MISRA-C contains a number of rules to ban sloppy use of integer literals in expression like this. 像这样的错误是为什么编码标准MISRA-C包含许多规则来禁止在这样的表达式中使用整数文字。 MISRA-C compliant code must use the u suffix after each integer literal (MISRA-C:2004 10.6) and the code is not allowed to perform bitwise operations on signed integers (MISRA-C:2004 12.7). 符合MISRA-C的代码必须在每个整数文字后使用u后缀(MISRA-C:2004 10.6),并且不允许代码对有符号整数执行按位运算(MISRA-C:2004 12.7)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM