c# - 在 ushort 中设置位范围

标签 c# c++ bit-manipulation

假设我有一个 ushort 值,我想设置位 1 到 4(假设 0 是 LSB,15 是 MSB)。

在 C++ 中,您可以定义一个映射特定位的结构:

struct KibblesNBits
{
   unsigned short int TheStart: 1;
   unsigned short int TheMeat:  4;
   unsigned short int TheRest: 11;
}

然后您可以直接为“TheMeat”赋值。我正在寻找在 C# 中做类似的事情。理想情况下,我想要一个如下所示的函数定义:

public ModValue SetRange<ModValue, RangeValue>(ModValue valueToMod, int startIndex, int endIndex, RangeValue rangeValueToAssign)

还需要验证 rangeValueToAssign 不超过最大大小(假设值是无符号的,从 0 到最大值)。因此,如果范围是从 1 到 4,这是 4 位,范围将从 0 到 15。如果超出这些限制,则抛出异常。

我没有在 BitConverter 类中找到任何可以做这样的事情的东西。我能想到的最好的方法是使用手动换档运算符(operator)。有更好的方法吗?

编辑:非通用版本可能看起来像这样:

  public static ushort SetRange(ushort valueToMod, int startIndex, int endIndex, ushort rangeValueToAssign)
  {
     // Determine max value
     ushort max_value = Convert.ToUInt16(Math.Pow(2.0, (endIndex - startIndex) + 1.0) - 1);
     if(rangeValueToAssign > max_value) throw new Exception("Value To Large For Range");
     // Shift the value and add it to the orignal (effect of setting range?)
     ushort value_to_add = (ushort)(rangeValueToAssign << startIndex);
     return (ushort)(valueToMod + value_to_add);
  }

地点:

ushort new_val = SetRange(120, 1, 2, 3);

会导致“new_val”被设置为 126。

最佳答案

public static int SetRange(int num, int from, int to, int value)
{
    if (from < 0 || from > to || to >= 32) throw new ArgumentException("from/to are not valid");
    if (value >= (2 << (to - from)) && (to - from < 31)) throw new ArgumentException("value is too large");
    return num & ~(((2 << to) - 1) - ((1 << from) - 1)) | (value << from);
}

没有 for 循环或 Math.Pow(这非常慢,比 Sin/Cos 等慢得多)。

至于通用 - 抱歉,那行不通。 C#(或.NET)中没有数字的基类型,所以这是不可能的。看起来您正在尝试使用 C++ 中的模板函数之类的泛型——不要被相似的外观所迷惑;它们完全不同。

如果您必须有不同的类型,我建议改用重载。

public static int SetRange(int num, int from, int to, int value)
{
    if (from < 0 || from > to || to >= 32) throw new ArgumentException("from/to are not valid");
    if (value >= (2 << (to - from)) && (to - from < 31)) throw new ArgumentException("value is too large");
    return num & ~(((2 << to) - 1) - ((1 << from) - 1)) | (value << from);
}

public static ushort SetRange(ushort num, int from, int to, ushort value)
{
    if (from < 0 || from > to || to >= 16) throw new ArgumentException("from/to are not valid");
    if (value >= (2 << (to - from))) throw new ArgumentException("value is too large");
    return (ushort) (num & ~(((2 << to) - 1) - ((1 << from) - 1)) | (value << from));
}

但是,在 C# 中,始终使用 int(如果需要,也可以使用 long)可能更为惯用。

关于c# - 在 ushort 中设置位范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2246228/

相关文章:

c - 根据位掩码合并两个位域

c# - EF 查询 Oracle 抛出 "ORA-12704: character set mismatch"

c# - EF 代码第一个错误 "Entity Set already defined"

c++ - 连续输出(最多)4 个 vector 元素

c++ - 如何识别带有 char 指针的字符串?

c# - 高效的位重映射算法

c# - 将 JSON 反序列化为 IDictionary<string,object>

c# - 删除发送到 Json MVC 的对象的空属性

c++ - 链表内存管理

CSAPP : What should happen if I want to shift an 8-bit number 8 positions to the left