Просто наткнулся на это в поисках чего-то другого, может быть, немного поздно, но, возможно, это будет полезно для кого-то еще. AFAIAC все программисты на С должны начинать программировать на ассемблере.
В любом случае расширение знака намного проще, чем предложения. Просто убедитесь, что вы используете подписанные переменные, а затем используйте 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 переводит >> в Arithmetic Shift Right, который сохраняет знак. Это поведение не зависит от платформы.
Итак, предполагая, что значение начинается с 0x1ff, тогда мы имеем, << 16 будет SL (Shift Left) значение, так что 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