7

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

4

5 回答 5

18

为什么会出错:

int16_t s = -890;
int32_t i = s;  //this does the job, doesn't it?
于 2011-06-02T13:47:02.630 回答
12

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

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

或者更好(如果通过 a 可能会产生警告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类型。

于 2011-06-02T13:49:27.640 回答
8

只是在寻找其他东西时遇到了这个问题,可能有点晚了,但也许它对其他人有用。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;
}

这会产生以下输出:

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
于 2012-11-06T18:48:15.787 回答
6

尝试:

int signExtension(int instr) {
    int value = (0x0000FFFF & instr);
    int mask = 0x00008000;
    if (mask & instr) {
        value += 0xFFFF0000;
    }
    return value;
}
于 2011-06-02T13:42:00.730 回答
3

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

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

如果高 16 位已经为零:

(n ^ 0x8000) - 0x8000

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

于 2018-08-22T00:40:48.043 回答