【问题标题】:Sign extending from a constant bit width in C#从 C# 中的恒定位宽扩展符号
【发布时间】:2011-04-28 05:20:48
【问题描述】:

我有一个长度为 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# c binary bit-manipulation signed


【解决方案1】:

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

int fiveBits = normal & 0x1f;

反过来:

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

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

【讨论】:

  • 嘿乔恩。简单地说,我有一个值,它包含在一个 sbyte 中。根据定义,这个 sbyte 的长度是 8 位。我只关心前 5 位。我试图从这 5 位中提取的值实际上是一个半字节(4 位)的长度,因此保持在 0-15 之间的值。 5 咬确定符号(从而使我的可能值范围为 -16 到 +15)。因此,例如,如果我的 sbyte 值等于 10(二进制 01010),那么我的结果应该是 10。如果我的 sbyte 值等于 26(二进制 11010),那么我的结果应该是 -6(因为我的第 5 位是1 或签名)。这有意义吗?
  • @icemanind:所以我给了你一个使用int 的例子——你应该能够在每种情况下都将结果转换为sbyte
  • 有点小气,但我会选择int normal = (fiveBits &amp; 16) == 0 ? fiveBits : fiveBits | -32;。小于比较实际上并不能确保设置了第 5 位(符号位)。使用按位与运算仅测试位 5。如果您在周围反弹了很多这些值,您可以创建一个 FiveBits 结构并实现与 Int32 的隐式类型转换。例如:public static implicit operator int(FiveBits fiveBits) { return (fiveBits.Value &amp; 16) == 0 ? fiveBits.Value : fiveBits.Value | -32; }。这将提供类型安全并防止转换错误。好玩!
【解决方案2】:

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

当然,这取决于是否有有效的算术移位操作。抽象的 C 语言没有(不管它是否有效,它是由实现定义的),但大多数实现都可以。我不确定 C#,但我猜它有一个。

【讨论】:

    【解决方案3】:

    我只是在编写一个 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
    }
    

    【讨论】:

    • 不是sizeof(int)-5,而是sizeof(int)*8-5,或者,根据C#定义,直接32-5
    【解决方案4】:

    从您的问题来看,您似乎希望拥有一个可以轻松转换为 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
    

    【讨论】:

      【解决方案5】:

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

      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));
          }
      }
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-16
        • 2012-09-30
        • 2015-05-29
        相关资源
        最近更新 更多