在C中将符号扩展名从16位扩展到32位

时间:2011-06-02 13:34:29

标签: c binary integer sign

我必须为16位整数执行符号扩展,出于某种原因,它似乎无法正常工作。谁能告诉我代码中的bug在哪里?我已经工作了几个小时。

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位的数字。

5 个答案:

答案 0 :(得分:17)

为什么错误:

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

答案 1 :(得分:12)

使用内置类型有什么问题?

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)

您显然需要为<stdint.h>int16_t数据类型添加int32_t

答案 2 :(得分:7)

刚刚碰到这个寻找别的东西,也许有点晚了,但也许它对其他人有用。 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编译器会翻译&gt;&gt;到算术右移保留符号。此行为与平台无关。

因此,假设该值以0x1ff开始,那么我们有,&lt;&lt; 16将SL(左移)值,因此instr现在是0xff80,然后是&gt;&gt; 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;
}

这会产生以下输出:

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

答案 3 :(得分:6)

尝试:

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

答案 4 :(得分:1)

人们指出了强制转换和左移,然后是算术右移。不需要分支的另一种方法:

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

如果高16位已经为零:

(n ^ 0x8000) - 0x8000

•社区Wiki,因为它来自"The Aggregate Magic Algorithms, Sign Extension"