C中从16位到32位的符号扩展



我必须对一个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_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开始,则我们有,<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,因为它是"聚合魔术算法,符号扩展"

中的一个想法

相关内容

  • 没有找到相关文章

最新更新