符号扩展到32位,从n位开始 - C

问题描述:

我是C新手,并通过位操作获得了一些练习。符号扩展到32位,从n位开始 - C

假设我有n位二进制补码数使得n> 0和n < 31.如果我知道的n提前大小,我怎么能签字扩展到32位?

如果n为16位,

int32_t extendMe(int16_t n) { 
    return (int32_t) n; 
} 

假设我有数据的定义。

假设我有一个我想签名的n位值可以扩展到32位,我该怎么做到这一点?

谢谢。

+0

你的意思是你想对二进制补码进行操作,而不管你的编译器使用负数的表示吗?或者这只是一个假设?如果您确实是指前者,则必须使用**无符号**类型来完全控制所有(值)位。 –

+0

啊,是的,这就是我的意思。 – Kyle

+3

这通常会作为[integer promotion](http://en.cppreference.com/w/c/language/conversion#Integer_promotions)的一部分自动发生,例如,当编译器执行[常规算术转换](http:///en.cppreference.com/w/c/language/conversion#Usual_arithmetic_conversions)。 –

如果这真的是关于如何解释任意位模式为使用二进制补码在ň位表示的数字,这里的一些草率的示例代码这样做:

#include <stdio.h> 
#include <inttypes.h> 

// this assumes the number is in the least significant `bits`, with 
// the most significat of these being the sign bit. 
int32_t fromTwosComplement(uint32_t pattern, unsigned int bits) 
{ 
    // read sign bit 
    int negative = !!(pattern & (1U << (bits-1))); 

    // bit mask for all bits *except* the sign bit 
    uint32_t mask = (1U << (bits-1)) - 1; 

    // extract value without sign 
    uint32_t val = pattern & mask; 

    if (negative) 
    { 
     // if negative, apply two's complement 
     val ^= mask; 
     ++val; 
     return -val; 
    } 
    else 
    { 
     return val; 
    } 
} 

int main(void) 
{ 
    printf("%" PRId32 "\n", fromTwosComplement(0x1f, 5)); // output -1 
    printf("%" PRId32 "\n", fromTwosComplement(0x01, 5)); // output 1 
} 

一个n位2的补数是负的,如果位n - 1是1.在这种情况下,您想要用1填充从n到31的所有位。如果它为零,为了完整性,您可能还想用0填充从n到31的位。因此,您需要一个掩码,您可以使用位操作来完成上述操作。这很容易做到。假设你的n个位2的补数以uint32_t的召开方式:

int32_t signExtend(uint32_t number, int n) 
{ 
    uint32_t ret; 
    uint32_t mask = 0xffffffff << n; 
    if (number & (1 << (n - 1)) != 0) 
    { 
     // number is negative 
     ret = number | mask; 
    } 
    else 
    { 
     // number is positive 
     ret = number & ~mask; 
    } 
    return (int32_t) ret; 
} 

完全未经测试的最后一行可能是UB,但它应该在大多数实施工作。