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

我必须为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位的数字。

尝试:

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

为什么错:

 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) ,将signExtension(value)替换为((int32_t)(int16_t)value)

你显然需要为int16_tint32_t数据类型包含

只是碰到了这个寻找别的东西,也许有点晚了,但也许它对其他人有用。 AFAIAC所有C程序员都应该开始编程汇编程序。

无论如何,标志延伸比提案容易得多。 只需确保使用签名变量然后使用2class制。

 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  #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 

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

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

如果高16位已经为零:

 (n ^ 0x8000) - 0x8000 

•社区维基,因为它是“聚合魔术算法,符号扩展”的想法