簡體   English   中英

C 中從 16 位到 32 位的符號擴展

[英]Sign extension from 16 to 32 bits in C

我必須為 16 位 integer 進行符號擴展,由於某種原因,它似乎無法正常工作。 誰能告訴我代碼中的錯誤在哪里? 我已經為此工作了好幾個小時。

int signExtension(int instr) {
    int value = (0x0000FFFF & instr);
    int mask = 0x00008000;
    int sign = (mask & instr) >> 15;
    if (sign == 1)
        value += 0xFFFF0000;
    return value;
}

指令(instr)是 32 位,在它里面我有一個 16 位的數字。

為什么會出錯:

int16_t s = -890;
int32_t i = s;  //this does the job, doesn't it?

使用內置類型有什么問題?

int32_t signExtension(int32_t instr) {
    int16_t value = (int16_t)instr;
    return (int32_t)value;
}

或者更好(如果通過int32_t可能會產生警告)

int32_t signExtension(int16_t instr) {
    return (int32_t)instr;
}

或者,對於所有重要的事情,將signExtension(value)替換為((int32_t)(int16_t)value)

您顯然需要為int16_tint32_t數據類型包含<stdint.h>

只是在尋找其他東西時遇到了這個問題,可能有點晚了,但也許它對其他人有用。 AFAIAC 所有 C 程序員都應該開始編程匯編程序。

無論如何,擴展符號比提案要容易得多。 只需確保您使用有符號變量,然后使用 2 個班次即可。

long value;   // 32 bit storage
value=0xffff; // 16 bit 2's complement -1, value is now 0x0000ffff
value = ((value << 16) >> 16); // value is now 0xffffffff

如果變量有符號,則 C 編譯器將 >> 轉換為保留符號的算術右移。 此行為與平台無關。

因此,假設值以 0x1ff 開頭,那么我們有,<< 16 將 SL(左移)該值,因此 instr 現在是 0xff80,然后 >> 16 將 ASR 值因此 instr 現在是 0xffff。

如果您真的想玩宏,請嘗試這樣的事情(GCC 中的語法在 MSVC 中沒有嘗試過)。

#include <stdio.h>

#define INT8 signed char
#define INT16 signed short
#define INT32 signed long
#define INT64 signed long long
#define SIGN_EXTEND(to, from, value) ((INT##to)((INT##to)(((INT##to)value) << (to - from)) >> (to - from)))

int main(int argc, char *argv[], char *envp[])
{
    INT16 value16 = 0x10f;
    INT32 value32 = 0x10f;
    printf("SIGN_EXTEND(8,3,6)=%i\n", SIGN_EXTEND(8,3,6));
    printf("LITERAL         SIGN_EXTEND(16,9,0x10f)=%i\n", SIGN_EXTEND(16,9,0x10f));
    printf("16 BIT VARIABLE SIGN_EXTEND(16,9,0x10f)=%i\n", SIGN_EXTEND(16,9,value16));
    printf("32 BIT VARIABLE SIGN_EXTEND(16,9,0x10f)=%i\n", SIGN_EXTEND(16,9,value32));

    return 0;
}

這將產生以下 output:

SIGN_EXTEND(8,3,6)=-2
LITERAL         SIGN_EXTEND(16,9,0x10f)=-241
16 BIT VARIABLE SIGN_EXTEND(16,9,0x10f)=-241
32 BIT VARIABLE SIGN_EXTEND(16,9,0x10f)=-241

嘗試:

int signExtension(int instr) {
    int value = (0x0000FFFF & instr);
    int mask = 0x00008000;
    if (mask & instr) {
        value += 0xFFFF0000;
    }
    return value;
}

人們指出鑄造和左移,然后是算術右移。 另一種不需要分支的方式:

(0xffff & n ^ 0x8000) - 0x8000

如果高 16 位已經為零:

(n ^ 0x8000) - 0x8000

• 社區維基,因為它是“聚合魔法算法,符號擴展”中的一個想法

暫無
暫無

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

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