将位域转换为数组

4

我是一名有用的助手,可以为您进行文本翻译。

我有一个名为Forced的uint,其中包含32位。

我做这样的事情:

if(Forced & 512)
   doStuff();

我希望你能将“forced”加入到一个数组中,最终数组的内容会变成:
if(ForcedArray[(int)Math.Log(512,2)])
   doStuff();

.NET中是否有便捷的方法来实现这一点?将位域转换为数组的便捷方法是什么?


7
为什么?使用“<<”像这样访问位非常简单:Forced & (1 << bitNumber)... - Alexei Levenkov
3个回答

4
您可以编写一个扩展方法来实现此功能:
public static class UIntExtensions
{
    public static bool IsBitSet(this uint i, int bitNumber)
    {
        return i & (1 << bitNumber) != 0;
    }
}

或者,如果你想用C#6的方式来实现:

public static class UIntExtensions
{
    public static bool IsBitSet(this uint i, int bitNumber) => (i & (1 << bitNumber)) != 0;
}

这很容易在代码中使用:

if(Forced.IsBitSet((int)Math.Log(512,2)))
   doStuff();

显然,需要添加一些检查以确保位数大于等于0或小于等于31,但您已经明白了这个想法。

3
使用位移操作访问整数的位,Forced & (1 << bitNumber)听起来是一个好方法(在Ron Beyer的回答中展示了对访问进行包装的不错的函数)。
代码的大多数读者将会对将紧凑的单词字段转换为像数组这样复杂的数据结构感到困惑。除非有其他原因(例如JSON序列化等外部API约束)或者可以显著提高可读性,否则请考虑避免这种情况。
作为中间方法,您可以创建小的包装结构,它持有整数值并额外公开了对每个位的索引访问(最好是不可变的)。
如果您真的想要一个数组,基本的for循环或LINQ可以用来将每个位转换为布尔值。即使只有一个整数(可能需要根据您需要的位调整顺序,此处将最低位放在第一位)。
var array = Enumerable.Range(0, 32)
  .Select(bitNumber => (Forced & (1 << bitNumber)) !=0)
  .ToArray();

位数组的合法目的通常是为了微调性能和/或内存使用。我不确定是否建议使用Linq答案,因为它很可能会使微优化失效。然而,在许多情况下,位数组可能用于不需要该优化的上下文中... - Eric J.
1
@EricJ。我严重怀疑OP正在寻找微小的优化 - (int)Math.Log(512,2)看起来不像是在性能敏感的代码中使用的任何东西。可能有其他原因 - 也许使用数组可以使特定的代码更易读?(如果性能/大小很重要,可以将整数包装到具有索引器的结构体中) - Alexei Levenkov
也许不是楼主,但我刚刚读了https://dev59.com/z3zaa4cB1Zd3GeqPS6z3,它提醒我人们有一种习惯,即复制并使用他们不完全理解的代码。因此,我更喜欢Ron给出的答案,或者你在问题下面的评论。 - Eric J.
1
@EricJ. :) 这甚至更奇怪 - 人们复制粘贴代码,然后将其交给其他人复制,第三个人不得不回到 SO 请求解释,就像在这个问题中发生的一样(http://stackoverflow.com/a/34275738/477420)。 - Alexei Levenkov

0
public static class UIntExtensions
{
    public static byte[] GetBitArray(this uint v)
    {
        var r = byte[32];
        for (var i = 0; i < 32; ++i)
        {
            r[i] = v & 1;
            v = v >> 1
        }
        return r;
    }
}

你能稍微解释一下你的代码吗?特别是,你会如何回答“将位字段转换为数组的便捷方法是什么?”这个问题?你应该知道你的回答已经被列入了待删除队列 - Wai Ha Lee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接