C中的符号扩展,加法和减法二进制

时间:2015-03-25 02:24:48

标签: c bitwise-operators sign-extension

如何在C代码中实现从16位扩展到32位的符号?
我应该使用按位运算符。我还需要加减;任何人都能指出我正确的方向吗?我做了前4,但我对其余的感到困惑。对于其中一个案例,我必须在某处包含一个for循环。

我不允许使用任何算术运算符(+-/*)和if语句。

以下是我正在编辑的switch语句的代码:

unsigned int csc333ALU(const unsigned int opcode,
               const unsigned int argument1,
               const unsigned int argument2) {
unsigned int result;

switch(opcode) {
  case(0x01): // result = NOT argument1
    result = ~(argument1);
    break;
  case(0x02): // result = argument 1 OR argument 2
    result = argument1 | argument2;
    break;
  case(0x03): // result = argument 1 AND argument 2
    result = argument1 & argument2;
    break;
  case(0x04): // result = argument 1 XOR argument 2
    result = argument1 ^ argument2;
    break;
  case(0x05): // result = 16 bit argument 1 sign extended to 32 bits
    result = 0x00000000;
    break;
  case(0x06): // result = argument1 + argument2
    result = 0x00000000;
    break;
  case(0x07): // result = -argument1. In two's complement, negate and add 1.
    result = 0x00000000;
    break;
  default:
    printf("Invalid opcode: %X\n", opcode);
    result = 0xFFFFFFFF;
  }

3 个答案:

答案 0 :(得分:1)

符号扩展的部分答案:

result = (argument1 & 0x8000) == 0x8000 ? 0xFFFF0000 | argument1 : argument1;

答案 1 :(得分:1)

要将16位数字符号扩展为32位,需要将位15复制到高位。天真的方法是使用16条指令,将第15位复制到第16位,然后是17,然后是18,依此类推。但是你可以通过使用先前复制的比特并将每次复制的比特数加倍来更有效地完成它:

unsigned int ext = (argument1 & 0x8000U) << 1;
ext |= ext << 1;
ext |= ext << 2;
ext |= ext << 4;
ext |= ext << 8;
result = (argument1 & 0xffffU) | ext;

添加两个32位数字&#34;手动&#34;然后你可以一点一点地做。

unsigned carry = 0;
result = 0;
for (int i = 0; i < 32; i++) {
    // Extract the ith bit from argument1 and argument 2.
    unsigned a1 = (argument1 >> i) & 1;
    unsigned a2 = (argument2 >> i) & 1;
    // The ith bit of result is set if 1 or 3 of a1, a2, carry is set.
    unsigned v = a1 ^ a2 ^ carry;
    result |= v << i;
    // The new carry is 1 if at least two of a1, a2, carry is set.
    carry = (a1 & a2) | (a1 & carry) | (a2 & carry);
}

减法适用于几乎完全相同的代码:a - b与两个补码算法中的a + (~b+1)相同。由于您不能简单地添加1,因此您可以通过将carry初始化为1而不是0来实现相同目标。

unsigned carry = 1;
result = 0;
for (int i = 0; i < 32; i++) {
    unsigned a1 = (argument1 >> i) & 1;
    unsigned a2 = (~argument2 >> i) & 1;
    unsigned v = a1 ^ a2 ^ carry;
    result |= v << i;
    carry = (a1 & a2) | (a1 & carry) | (a2 & carry);
}

为了找到两个补语而不做出否定,类似的想法也适用。按位否定然后添加1。添加1比添加argument2更简单,因此代码相应更简单。

result = ~argument1;
unsigned carry = 1;
for (int i = 0; i < 32 && carry; i++) {
    carry &= (result >> i);
    result |= (1 << i);        
}

答案 2 :(得分:0)

将标记从short int扩展到int ....

short int iShort = value;

int i = iShort;  // compiler automatically creates code that performs sign extension

注意:从i转到iShort将生成编译器。

然而,对于其他情况......

无需进行比较,&将导致单个位为0或1,并确保将计算部分转换为int

int i = (short int argument&0x8000)? (int)(0xFFFF000 | (int)argument) : (int)argument;