首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >设置ushort中的位范围

设置ushort中的位范围
EN

Stack Overflow用户
提问于 2010-02-12 01:21:38
回答 5查看 2.5K关注 0票数 3

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

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

代码语言:javascript
复制
struct KibblesNBits
{
   unsigned short int TheStart: 1;
   unsigned short int TheMeat:  4;
   unsigned short int TheRest: 11;
}

然后你可以直接给'TheMeat‘赋值。我希望在C#中做一些类似的事情。理想情况下,我希望函数定义看起来像这样:

代码语言:javascript
复制
public ModValue SetRange<ModValue, RangeValue>(ModValue valueToMod, int startIndex, int endIndex, RangeValue rangeValueToAssign)

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

我在BitConverter类中找不到任何可以这样做的东西。我能想到的最好的方法是使用manaul移位运算符。有没有更好的方法来做这件事?

编辑:非通用版本可能如下所示:

代码语言:javascript
复制
  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);
  }

其中:

代码语言:javascript
复制
ushort new_val = SetRange(120, 1, 2, 3);

将导致'new_val‘被设置为126。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2018-08-08 01:35:43

这里的固定类型回答帮助我得到了最初要求的通用解决方案。这是最终的代码(带有getter奖励)。

代码语言:javascript
复制
/// <summary>Gets the bit array value from the specified range in a bit vector.</summary>
/// <typeparam name="T">The type of the bit vector. Must be of type <see cref="IConvertible"/>.</typeparam>
/// <param name="bits">The bit vector.</param>
/// <param name="startIdx">The zero-based start index of the bit range to get.</param>
/// <param name="count">The number of sequential bits to fetch starting at <paramref name="startIdx"/>.</param>
/// <returns>The value of the requested bit range.</returns>
public static T GetBits<T>(T bits, byte startIdx, byte count) where T : IConvertible
{
    if (startIdx >= (Marshal.SizeOf(typeof(T)) * 8)) throw new ArgumentOutOfRangeException(nameof(startIdx));
    if (count + startIdx > (Marshal.SizeOf(typeof(T)) * 8)) throw new ArgumentOutOfRangeException(nameof(count));
    return (T)Convert.ChangeType((bits.ToInt64(null) >> startIdx) & ((1 << count) - 1), typeof(T));
}

/// <summary>Sets the bit values at the specified range in a bit vector.</summary>
/// <typeparam name="T">The type of the bit vector. Must be of type <see cref="IConvertible"/>.</typeparam>
/// <typeparam name="TValue">The type of the value. Must be of type <see cref="IConvertible"/>.</typeparam>
/// <param name="bits">The bit vector.</param>
/// <param name="startIdx">The zero-based start index of the bit range to set.</param>
/// <param name="count">The number of sequential bits to set starting at <paramref name="startIdx"/>.</param>
/// <param name="value">The value to set within the specified range of <paramref name="bits"/>.</param>
public static void SetBits<T, TValue>(ref T bits, byte startIdx, byte count, TValue value) where T : IConvertible where TValue : IConvertible
{
    if (startIdx >= (Marshal.SizeOf(typeof(T)) * 8)) throw new ArgumentOutOfRangeException(nameof(startIdx));
    if (count + startIdx > (Marshal.SizeOf(typeof(T)) * 8)) throw new ArgumentOutOfRangeException(nameof(count));
    var val = value.ToInt64(null);
    if (val >= (1 << count)) throw new ArgumentOutOfRangeException(nameof(value));
    bits = (T)Convert.ChangeType(bits.ToInt64(null) & ~(((1 << count) - 1) << startIdx) | (val << startIdx), typeof(T));
}
票数 1
EN

Stack Overflow用户

发布于 2010-02-14 21:57:08

代码语言:javascript
复制
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)中没有numbers的基类型,所以这是不可能的。看起来您正在尝试使用泛型,比如C++中的模板函数-不要被相似的外观所蒙蔽;它们是完全不同的。

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

代码语言:javascript
复制
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 )可能更合适。

票数 2
EN

Stack Overflow用户

发布于 2010-02-12 01:37:00

如果您需要这种类型的访问,可以考虑使用BitVector32BitArray,或者熟悉按位运算。您可以在C#中对结构进行显式布局(导致联合),但我不认为这对您有好处。它主要针对互操作场景。

对于info,按位运算符主要在uint/int/ulong/long上工作-而不是更小的整数类型。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2246228

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档