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

问题描述 投票:0回答:3

我是 C 语言新手,正在练习位操作。

假设我有一个 n 位二进制补码数,使得 n > 0 且 n < 31. If I know the size of n in advance, how can I sign extend it to 32 bits?

如果n是16位,

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

假设我有数据定义。

假设我有一个 n 位值,我想将其扩展为 32,我该如何实现这一点?

谢谢你。

c bit
3个回答
2
投票

如果这确实是将任意位模式解释为使用二进制补码以 n 位表示的数字,那么这里有一些草率的示例代码:

#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
}

1
投票

如果位 n - 1 为 1,则 n 位 2 的补码为负数。在这种情况下,您需要用 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,但它应该适用于大多数实现。


0
投票

5年了,答案中只有分支示例?好的,我们开始吧:

#include "stdint.h"
#include "assert.h"

/** Convert a bit pattern as n-bit two's complement number up to 32 bits */
int32_t sgnext32(uint32_t pattern, int nbits)
{
    assert(nbits > 0 && nbits <= 32);
    uint32_t sgnbit = 1L << (nbits - 1);
    uint32_t lsmask = sgnbit | (sgnbit - 1);
    return (int32_t)((pattern + sgnbit) & lsmask) - sgnbit;
}

我们在这里所做的是,通过添加

<MIN_INT, MAX_INT>
(
<0, MAX_UINT>
),将二进制补码模式从其
abs(MIN_INT)
范围带到
sgnbit
范围,然后将其剪辑为仅 n 位 (
lsmask
) 并恢复二进制补码内容,但在 32 位空间中。 这也适用于
nbits = 32
,因为在这种情况下,32 位溢出的工作方式与我们应用的掩码完全相同。

int main()
{
    assert((int32_t) 0 == sgnext32(0, 1));
    assert((int32_t) -1 == sgnext32(1, 1));

    assert((int32_t) 0 == sgnext32(0, 2));
    assert((int32_t) 1 == sgnext32(1, 2));
    assert((int32_t) -1 == sgnext32(3, 2));
    assert((int32_t) -2 == sgnext32(2, 2));

    assert((int32_t) 0 == sgnext32(0, 15));
    assert((int32_t) 0x3fff == sgnext32(0x3fff, 15));
    assert((int32_t) -0x4000 == sgnext32(0x4000, 15));
    assert((int32_t) -1 == sgnext32(0x7fff, 15));
    assert((int32_t) -2 == sgnext32(0x7ffe, 15));

    assert((int32_t) 0 == sgnext32(0, 24));
    assert((int32_t) 0x7fffff == sgnext32(0x7fffff, 24));
    assert((int32_t) -0x800000 == sgnext32(0x800000, 24));
    assert((int32_t) -1 == sgnext32(0xffffff, 24));
    assert((int32_t) -2 == sgnext32(0xfffffe, 24));

    assert((int32_t) 0 == sgnext32(0, 32));
    assert((int32_t) 0x7fffffff == sgnext32(0x7fffffff, 32));
    assert((int32_t) -0x80000000 == sgnext32(0x80000000, 32));
    assert((int32_t) -1 == sgnext32(0xffffffff, 32));
    assert((int32_t) -2 == sgnext32(0xfffffffe, 32));
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.