[英]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_t
和int32_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.