C#中的位字段

我有一个需要填充并写入磁盘的结构(实际上有几个)。


一个例子是:


byte-6    

bit0 - original_or_copy  

bit1 - copyright  

bit2 - data_alignment_indicator  

bit3 - PES_priority  

bit4-bit5 - PES_scrambling control.  

bit6-bit7 - reserved  

在CI中可能会执行以下操作:


struct PESHeader  {

    unsigned reserved:2;

    unsigned scrambling_control:2;

    unsigned priority:1;

    unsigned data_alignment_indicator:1;

    unsigned copyright:1;

    unsigned original_or_copy:1;

};

有什么方法可以在C#中执行此操作,从而使我能够使用结构取消引用点运算符访问这些位?


对于两个结构,我只需要包装访问器函数中的位移即可。


我有大量的结构要以这种方式处理,因此我正在寻找更易于阅读和编写的东西。


慕村9548890
浏览 482回答 3
3回答

拉莫斯之舞

我可能会使用属性将某些东西组合在一起,然后使用一个转换类将适当地归因于结构的结构转换为位域基元。就像是...using System;namespace BitfieldTest{&nbsp; &nbsp; [global::System.AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]&nbsp; &nbsp; sealed class BitfieldLengthAttribute : Attribute&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; uint length;&nbsp; &nbsp; &nbsp; &nbsp; public BitfieldLengthAttribute(uint length)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.length = length;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public uint Length { get { return length; } }&nbsp; &nbsp; }&nbsp; &nbsp; static class PrimitiveConversion&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; public static long ToLong<T>(T t) where T : struct&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; long r = 0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int offset = 0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // For every field suitably attributed with a BitfieldLength&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; foreach (System.Reflection.FieldInfo f in t.GetType().GetFields())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; object[] attrs = f.GetCustomAttributes(typeof(BitfieldLengthAttribute), false);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (attrs.Length == 1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; uint fieldLength&nbsp; = ((BitfieldLengthAttribute)attrs[0]).Length;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Calculate a bitmask of the desired length&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; long mask = 0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i < fieldLength; i++)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mask |= 1 << i;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r |= ((UInt32)f.GetValue(t) & mask) << offset;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; offset += (int)fieldLength;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return r;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; struct PESHeader&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; [BitfieldLength(2)]&nbsp; &nbsp; &nbsp; &nbsp; public uint reserved;&nbsp; &nbsp; &nbsp; &nbsp; [BitfieldLength(2)]&nbsp; &nbsp; &nbsp; &nbsp; public uint scrambling_control;&nbsp; &nbsp; &nbsp; &nbsp; [BitfieldLength(1)]&nbsp; &nbsp; &nbsp; &nbsp; public uint priority;&nbsp; &nbsp; &nbsp; &nbsp; [BitfieldLength(1)]&nbsp; &nbsp; &nbsp; &nbsp; public uint data_alignment_indicator;&nbsp; &nbsp; &nbsp; &nbsp; [BitfieldLength(1)]&nbsp; &nbsp; &nbsp; &nbsp; public uint copyright;&nbsp; &nbsp; &nbsp; &nbsp; [BitfieldLength(1)]&nbsp; &nbsp; &nbsp; &nbsp; public uint original_or_copy;&nbsp; &nbsp; };&nbsp; &nbsp; public class MainClass&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; public static void Main(string[] args)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PESHeader p = new PESHeader();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p.reserved = 3;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p.scrambling_control = 2;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p.data_alignment_indicator = 1;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; long l = PrimitiveConversion.ToLong(p);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (int i = 63; i >= 0; i--)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.Write( ((l & (1l << i)) > 0) ? "1" : "0");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.WriteLine();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}产生预期的... 000101011。当然,它需要更多的错误检查和更精巧的键入,但是(我认为)该概念是合理的,可重用的,并且可以让您轻松打出一打维护的结构。

红颜莎娜

通过使用枚举,您可以执行此操作,但是看起来很尴尬。[Flags]public enum PESHeaderFlags{&nbsp; &nbsp; IsCopy = 1, // implied that if not present, then it is an original&nbsp; &nbsp; IsCopyrighted = 2,&nbsp; &nbsp; IsDataAligned = 4,&nbsp; &nbsp; Priority = 8,&nbsp; &nbsp; ScramblingControlType1 = 0,&nbsp; &nbsp; ScramblingControlType2 = 16,&nbsp; &nbsp; ScramblingControlType3 = 32,&nbsp; &nbsp; ScramblingControlType4 = 16+32,&nbsp; &nbsp; ScramblingControlFlags = ScramblingControlType1 | ScramblingControlType2 | ... ype4&nbsp; &nbsp; etc.}

千巷猫影

您想要StructLayoutAttribute[StructLayout(LayoutKind.Explicit, Size=1, CharSet=CharSet.Ansi)]public struct Foo&nbsp;{ [FieldOffset(0)]public byte original_or_copy;&nbsp;&nbsp; [FieldOffset(0)]public byte copyright;&nbsp; [FieldOffset(0)]public byte data_alignment_indicator;&nbsp;&nbsp; [FieldOffset(0)]public byte PES_priority;&nbsp;&nbsp; [FieldOffset(0)]public byte PES_scrambling_control;&nbsp;&nbsp; [FieldOffset(0)]public byte reserved;&nbsp;}这实际上是一个并集,但您可以将其用作位域-您只需要知道每个字段的位应该在字节中的哪个位置即可。实用程序函数和/或与AND相对的常量会有所帮助。const byte _original_or_copy = 1;const byte _copyright&nbsp; &nbsp; &nbsp; &nbsp; = 2;//bool ooo = foo.original_or_copy();static bool original_or_copy(this Foo foo)&nbsp;{ return&nbsp; (foo.original_or_copy & _original_or_copy)&nbsp; == original_or_copy;}&nbsp; &nbsp;&nbsp;还有LayoutKind.Sequential,它可以让您以C方式进行操作。
打开App,查看更多内容
随时随地看视频慕课网APP