簡體   English   中英

uint64_t變量中C的按位移位運算

[英]Bitwise shift operation in C on uint64_t variable

我有以下示例代碼:

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是負數,因此它的符號擴展方式不同。

其他海報已經說明了為什么會這樣做。 但要獲得預期的結果:

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

您的程序中有未定義的行為,因此可能發生任何事情。

  • 整數文字0xF或0xFF的類型為int ,相當於signed int 在這個特定的平台上, int顯然是32位。
  • 整數文字24也是(帶符號) int
  • 當編譯器評估<< operation時,兩個操作數都是(signed) int因此不會發生隱式類型的提升。 因此<<操作的結果也是(簽名的) int
  • 值0xF << 24 = 0x0F000000作為非負值適合(帶符號) int ,因此一切正常。
  • 值0xFF << 24 = 0xFF000000 不適合 (signed) int 在這里,調用未定義的行為,並且可能發生任何事情。

ISO 9899:2011 6.5.7 / 4:

“E1 << E2的結果是E1左移E2位位置;空位用零填充。” / - /

“如果E1具有帶符號類型和非負值,並且E1×2E2在結果類型中可表示,那么這就是結果值;否則,行為是未定義的。

因此不能使用表達式0xFF << 24。 該程序可以隨后打印任何垃圾值。

但如果我們忽略那一個並專注於0x0F <24:

  • 0x0F000000仍然是(簽名) int 〜運算符適用於此。
  • 結果是0xF0FFFFFF,它仍然是一個signed int。 幾乎在任何系統上,這個32位十六進制等於二進制補碼中的負數。
  • 在賦值期間,此signed int將轉換為uint64_t類型。 這分兩步完成,首先將其轉換為帶符號的64位,然后將帶符號的64轉換為無符號64。

像這樣的錯誤是為什么編碼標准MISRA-C包含許多規則來禁止在這樣的表達式中使用整數文字。 符合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