我必须对一个16位整数进行符号扩展,但由于某种原因,它似乎无法正常工作。有人能告诉我代码中的错误在哪里吗?我已经做了好几个小时了。
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;
}
或者,不管怎样,用((int32_t)(int16_t)value)
代替signExtension(value)
对于int16_t
和int32_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开始,则我们有,<lt;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)=%in", SIGN_EXTEND(8,3,6));
printf("LITERAL SIGN_EXTEND(16,9,0x10f)=%in", SIGN_EXTEND(16,9,0x10f));
printf("16 BIT VARIABLE SIGN_EXTEND(16,9,0x10f)=%in", SIGN_EXTEND(16,9,value16));
printf("32 BIT VARIABLE SIGN_EXTEND(16,9,0x10f)=%in", 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
尝试:
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
•社区wiki,因为它是"聚合魔术算法,符号扩展"