简体   繁体   English

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

[英]Sign extension from 16 to 32 bits in C

I have to do a sign extension for a 16-bit integer and for some reason, it seems not to be working properly.我必须为 16 位 integer 进行符号扩展,由于某种原因,它似乎无法正常工作。 Could anyone please tell me where the bug is in the code?谁能告诉我代码中的错误在哪里? I've been working on it for hours.我已经为此工作了好几个小时。

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

The instruction (instr) is 32 bits and inside it I have a 16bit number.指令(instr)是 32 位,在它里面我有一个 16 位的数字。

Why is wrong with:为什么会出错:

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

what's wrong in using the builtin types?使用内置类型有什么问题?

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

or better yet (this might generate a warning if passed a int32_t )或者更好(如果通过int32_t可能会产生警告)

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

or, for all that matters, replace signExtension(value) with ((int32_t)(int16_t)value)或者,对于所有重要的事情,将signExtension(value)替换为((int32_t)(int16_t)value)

you obviously need to include <stdint.h> for the int16_t and int32_t data types.您显然需要为int16_tint32_t数据类型包含<stdint.h>

Just bumped into this looking for something else, maybe a bit late, but maybe it'll be useful for someone else.只是在寻找其他东西时遇到了这个问题,可能有点晚了,但也许它对其他人有用。 AFAIAC all C programmers should start off programming assembler. AFAIAC 所有 C 程序员都应该开始编程汇编程序。

Anyway sign extending is much easier than the proposals.无论如何,扩展符号比提案要容易得多。 Just make sure you are using signed variables and then use 2 shifts.只需确保您使用有符号变量,然后使用 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

If the variable is signed then the C compiler translates >> to Arithmetic Shift Right which preserves sign.如果变量有符号,则 C 编译器将 >> 转换为保留符号的算术右移。 This behaviour is platform independent.此行为与平台无关。

So, assuming that value starts of with 0x1ff then we have, << 16 will SL (Shift Left) the value so instr is now 0xff80, then >> 16 will ASR the value so instr is now 0xffff.因此,假设值以 0x1ff 开头,那么我们有,<< 16 将 SL(左移)该值,因此 instr 现在是 0xff80,然后 >> 16 将 ASR 值因此 instr 现在是 0xffff。

If you really want to have fun with macros then try something like this (syntax works in GCC haven't tried in MSVC).如果您真的想玩宏,请尝试这样的事情(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;
}

This produces the following output:这将产生以下 output:

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

Try:尝试:

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

People pointed out casting and a left shift followed by an arithmetic right shift.人们指出铸造和左移,然后是算术右移。 Another way that requires no branching:另一种不需要分支的方式:

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

If the upper 16 bits are already zeroes:如果高 16 位已经为零:

(n ^ 0x8000) - 0x8000

• Community wiki as it's an idea from "The Aggregate Magic Algorithms, Sign Extension" • 社区维基,因为它是“聚合魔法算法,符号扩展”中的一个想法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM