簡體   English   中英

為什么使用移位的此交換宏不適用於負數?

[英]Why doesn't this swap macro using shifts not work for negative numbers?

我在內置庫中找到了一些需要擴展的代碼。

但它似乎已損壞:

#define BSWAP16(__x)    ((((__x) >> 8) | ((__x) << 8)))

與以下功能不同:

__builtin_bswap16()

該程序證明了這一點。

#include <stdio.h>

#define BSWAP16(__x)    ((((__x) >> 8) | ((__x) << 8)))

int main(int argc, char* argv[])
{
    unsigned short a = (unsigned short)BSWAP16(0xff00);
    unsigned short b = __builtin_bswap16(0xff00);
    short c = (short)BSWAP16(-8);
    short d = __builtin_bswap16(-8);

    printf("a=%04x, b=%04x, c=%04x, d=%04x\n", a,b,c,d);
    return 0;
}

輸出:

a=00ff, b=00ff, c=ffffffff, d=fffff8ff

我不想要答案告訴我應該使用endian.h或__builtin_bswap16。 在此內部庫在此平台/編譯器配置上使用的目標平台上,我正在觸發此默認代碼,該代碼默認使用上述宏。

所以我的問題是。 為什么對負數不起作用?

如果我將-8表示為0xfff8的短值,則可以使用。

所以我想這與內部轉換為int有關。

如何修復此宏才能正常工作?

從草稿C99標准第6.5.7節“ 按位移位運算符”中說,負數向左移是不確定的行為( 強調我的 6.5.7 :)

E1 << E2的結果是E1左移E2位位置; 空位用零填充。 如果E1具有無符號類型,則結果的值為E1´2E2,比結果類型中可表示的最大值多模減1。 如果E1具有帶符號的類型和非負值 ,並且E1´2E2在結果類型中可表示,則這是結果值; 否則,行為是不確定的。

因此,左移-8的結果是不可預測的。 強制轉換為unsigned short應該可以解決以下問題:

BSWAP16((unsigned short)-8)

-8是一個整數常量(原 ),由於它沒有后綴,因此它是一個int值,因為int可以采用它的值。 假設32-bit 整數和二進制補碼將具有以下值:

 FFFFFFF8

強制轉換為unsigned short將刪除不需要的較高位。 強制轉換為unsigned int將無濟於事,因為它將保留較高的位。

右移負數也是實現定義:

E1 >> E2的結果是E1右移E2位位置。 如果E1具有無符號類型,或者E1具有帶符號類型和非負值,則結果的值是E1 / 2E2商的整數部分。 如果E1具有帶符號的類型和負值,則結果值是實現定義的。

移位之前,您應該屏蔽掉不需要的位。

#define BSWAP16(__x)    (((((__x) & 0xFF00) >> 8) | (((__x) & 0xFF) << 8)))

關於為什么不進行移位就不起作用的原因,請注意-8的確是0xFFFFFFF8 如果不進行屏蔽,則有很多較高的1位。 在計算過程中使用int

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM