C# 中从恒定位宽度扩展的符号

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

我有一个长度为 5 位的值。 4 位确定数字,第 5 位确定符号,从而保存 -16 和 +15 之间的任何值。如何在 C# 中实现从恒定位宽度扩展符号?我知道在 C 中,我可以使用类似下面的东西来完成这个:

int x; // convert this from using 5 bits to a full int
int r; // resulting sign extended number goes here
struct {signed int x:5;} s;
r = s.x = x;

如何在 C# 中做类似的事情?

c# c binary bit-manipulation signed
6个回答
4
投票

我只是编写一个 C 函数(因为我不太了解 C#),它将使用我知道 C# 中可用的操作来完成此操作。

int five_bit_to_signed(int five_bit) {
     int sh = (sizeof(int)*8)-5;
     int x = five_bit << sh; // puts your sign bit in the highest bit.
     return x >> sh;  // since x is signed this is an arithmatic signed shift
}

3
投票

不太清楚你的意思,但它可能很简单:

int fiveBits = normal & 0x1f;

反之亦然:

int normal =  fiveBits < 16 ? fiveBits : fiveBits | -32;

如果您可以建议一些原始输入和所需的输出,那将会有所帮助。


2
投票

先执行左移,然后执行算术右移,将符号位移至高位,然后再移回。算术右移将为您执行符号扩展。

当然,这取决于有效的算术移位运算。抽象 C 语言不这样做(无论是否有效,它都是实现定义的),但大多数实现都这样做。我不确定 C#,但我猜它有一个。


2
投票

我知道这是一个老问题,但对于未来的搜索者,我有更多信息。

C# 不支持自定义位宽,但它支持二进制运算和 getter/setter,这使得添加兼容层相对容易。例如,如果您想将原始数据存储在 byte _num 中,但希望能够使用标准 C# sbyte 与其进行交互,您可以使用以下命令:

byte _num;
sbyte num {
    get
    {
        return (sbyte)(((_num & 0x10) << 3) | (_num & 0x0F));
    }
    set
    {
        _num = (byte)((value & 0x0F) | ((value & 0x80) >> 3));
    }
}

这种 shell 在与低级固件或嵌入式项目交互时特别有用。


0
投票

从你的问题来看,你似乎希望有一个可以轻松地与

int
类型相互转换的结构:

struct FiveBit
{
  public int bits;

  public static implicit operator int(FiveBit f)
  {
    return (f.bits & 0x10) == 0 ? f.bits : f.bits | -32;
  }

  public static implicit operator FiveBit(int r)
  {
    return new FiveBit() { bits = r & 0x1f };
  }
}

这是一个用法示例:

class FiveBitTest
{
  static void Main(string[] args)
  {
    FiveBit f = new FiveBit();
    int r; // resulting sign extended number goes here

    f.bits = 0;
    r = f;
    Console.WriteLine("r = {0}, f.bits = 0x{1:X}", r, f.bits);

    f.bits = 0x1f;
    r = f;
    Console.WriteLine("r = {0}, f.bits = 0x{1:X}", r, f.bits);

    r = -2;
    f = r;
    Console.WriteLine("r = {0}, f.bits = 0x{1:X}", r, f.bits);
}

上面的输出是:

r = 0, f.bits = 0x0
r = -1, f.bits = 0x1F
r = -2, f.bits = 0x1E

0
投票

这是任何位宽的通用解决方案:

/// <summary>
/// Reinterprets a raw unsigned 32 bit integer as a signed value of a given width.
/// If the signed value is negative, the sign bits are extended to create the equivalent 32 bit signed integer.
/// </summary>
/// <param name="rawValue">The raw unsigned 32 bit integer</param>
/// <param name="width">The width of the signed integer, in bits</param>
/// <returns></returns>
int ExtendSign(uint rawValue, int width)
{
    // Generate a mask that extends from the most significant bit, down to and covering the sign bit of the value
    uint mask = (uint)(int.MinValue >> ((sizeof(int) * 8) - width));

    // Check if the value is negative
    if ((rawValue & mask) != 0)
    {
        // If so, extend the sign bit all the way to the MSB
        rawValue |= mask;
    }

    return (long)rawValue;
}

对于 5 位值的情况,您可以这样称呼它:

int r = ExtendSign(x, 5);

你可以

© www.soinside.com 2019 - 2024. All rights reserved.