我有一个结构,我需要填充和写入磁盘(实际上几个).
一个例子是:
byte-6
bit0 - original_or_copy
bit1 - copyright
bit2 - data_alignment_indicator
bit3 - PES_priority
bit4-bit5 - PES_scrambling control.
bit6-bit7 - reserved
Run Code Online (Sandbox Code Playgroud)
在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;
};
Run Code Online (Sandbox Code Playgroud)
有没有办法在C#中做到这一点,使我能够使用struct dereferencing点运算符访问位?
对于几个结构,我可以在访问器函数中进行包裹移位.
我有很多结构要以这种方式处理,所以我正在寻找一些更容易阅读和更快写的东西.
Ada*_*ght 53
我可能会使用属性拼凑一些东西,然后转换类将适当的属性结构转换为位域基元.就像是...
using System;
namespace BitfieldTest
{
[global::System.AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
sealed class BitfieldLengthAttribute : Attribute
{
uint length;
public BitfieldLengthAttribute(uint length)
{
this.length = length;
}
public uint Length { get { return length; } }
}
static class PrimitiveConversion
{
public static long ToLong<T>(T t) where T : struct
{
long r = 0;
int offset = 0;
// For every field suitably attributed with a BitfieldLength
foreach (System.Reflection.FieldInfo f in t.GetType().GetFields())
{
object[] attrs = f.GetCustomAttributes(typeof(BitfieldLengthAttribute), false);
if (attrs.Length == 1)
{
uint fieldLength = ((BitfieldLengthAttribute)attrs[0]).Length;
// Calculate a bitmask of the desired length
long mask = 0;
for (int i = 0; i < fieldLength; i++)
mask |= 1 << i;
r |= ((UInt32)f.GetValue(t) & mask) << offset;
offset += (int)fieldLength;
}
}
return r;
}
}
struct PESHeader
{
[BitfieldLength(2)]
public uint reserved;
[BitfieldLength(2)]
public uint scrambling_control;
[BitfieldLength(1)]
public uint priority;
[BitfieldLength(1)]
public uint data_alignment_indicator;
[BitfieldLength(1)]
public uint copyright;
[BitfieldLength(1)]
public uint original_or_copy;
};
public class MainClass
{
public static void Main(string[] args)
{
PESHeader p = new PESHeader();
p.reserved = 3;
p.scrambling_control = 2;
p.data_alignment_indicator = 1;
long l = PrimitiveConversion.ToLong(p);
for (int i = 63; i >= 0; i--)
{
Console.Write( ((l & (1l << i)) > 0) ? "1" : "0");
}
Console.WriteLine();
return;
}
}
}
Run Code Online (Sandbox Code Playgroud)
哪个产生了预期的... 000101011.当然,它需要更多的错误检查和稍微更健全的打字,但这个概念(我认为)是合理的,可重复使用的,并且让你可以轻松淘汰那些容易维护的结构.
adamw
ang*_*son 23
通过使用枚举,你可以做到这一点,但看起来很尴尬.
[Flags]
public enum PESHeaderFlags
{
IsCopy = 1, // implied that if not present, then it is an original
IsCopyrighted = 2,
IsDataAligned = 4,
Priority = 8,
ScramblingControlType1 = 0,
ScramblingControlType2 = 16,
ScramblingControlType3 = 32,
ScramblingControlType4 = 16+32,
ScramblingControlFlags = ScramblingControlType1 | ScramblingControlType2 | ... ype4
etc.
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*ade 18
[StructLayout(LayoutKind.Explicit, Size=1, CharSet=CharSet.Ansi)]
public struct Foo
{ [FieldOffset(0)]public byte original_or_copy;
[FieldOffset(0)]public byte copyright;
[FieldOffset(0)]public byte data_alignment_indicator;
[FieldOffset(0)]public byte PES_priority;
[FieldOffset(0)]public byte PES_scrambling_control;
[FieldOffset(0)]public byte reserved;
}
Run Code Online (Sandbox Code Playgroud)
这实际上是一个联合,但您可以将它用作位域 - 您只需要知道每个字段的位应该在字节中的哪个位置.效用函数和/或AND的常量可以提供帮助.
const byte _original_or_copy = 1;
const byte _copyright = 2;
//bool ooo = foo.original_or_copy();
static bool original_or_copy(this Foo foo)
{ return (foo.original_or_copy & _original_or_copy) == original_or_copy;
}
Run Code Online (Sandbox Code Playgroud)
还有LayoutKind.Sequential,它允许你以C方式进行.
Zby*_*byl 16
正如Christophe Lambrechts建议BitVector32提供解决方案.Jitted表现应该足够,但不确定.以下是说明此解决方案的代码:
public struct rcSpan
{
//C# Spec 10.4.5.1: The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration.
internal static readonly BitVector32.Section sminSection = BitVector32.CreateSection(0x1FFF);
internal static readonly BitVector32.Section smaxSection = BitVector32.CreateSection(0x1FFF, sminSection);
internal static readonly BitVector32.Section areaSection = BitVector32.CreateSection(0x3F, smaxSection);
internal BitVector32 data;
//public uint smin : 13;
public uint smin
{
get { return (uint)data[sminSection]; }
set { data[sminSection] = (int)value; }
}
//public uint smax : 13;
public uint smax
{
get { return (uint)data[smaxSection]; }
set { data[smaxSection] = (int)value; }
}
//public uint area : 6;
public uint area
{
get { return (uint)data[areaSection]; }
set { data[areaSection] = (int)value; }
}
}
Run Code Online (Sandbox Code Playgroud)
你可以用这种方式做很多事情.通过为每个字段提供手工访问器,您可以在不使用BitVector32的情况下做得更好:
public struct rcSpan2
{
internal uint data;
//public uint smin : 13;
public uint smin
{
get { return data & 0x1FFF; }
set { data = (data & ~0x1FFFu ) | (value & 0x1FFF); }
}
//public uint smax : 13;
public uint smax
{
get { return (data >> 13) & 0x1FFF; }
set { data = (data & ~(0x1FFFu << 13)) | (value & 0x1FFF) << 13; }
}
//public uint area : 6;
public uint area
{
get { return (data >> 26) & 0x3F; }
set { data = (data & ~(0x3F << 26)) | (value & 0x3F) << 26; }
}
}
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,最后一个手工制作的解决方案似乎是最方便,最简单,最短的解决方案.那当然只是我个人的偏好.
还有一个基于Zbyl的答案.这个对我来说更容易改变 - 我只需要调整sz0,sz1 ......并确保掩码#和loc#在Set/Get块中是正确的.
性能方面,它应该是相同的,因为它们都解决了38个MSIL语句.(常量在编译时解析)
public struct MyStruct
{
internal uint raw;
const int sz0 = 4, loc0 = 0, mask0 = ((1 << sz0) - 1) << loc0;
const int sz1 = 4, loc1 = loc0 + sz0, mask1 = ((1 << sz1) - 1) << loc1;
const int sz2 = 4, loc2 = loc1 + sz1, mask2 = ((1 << sz2) - 1) << loc2;
const int sz3 = 4, loc3 = loc2 + sz2, mask3 = ((1 << sz3) - 1) << loc3;
public uint Item0
{
get { return (uint)(raw & mask0) >> loc0; }
set { raw = (uint)(raw & ~mask0 | (value << loc0) & mask0); }
}
public uint Item1
{
get { return (uint)(raw & mask1) >> loc1; }
set { raw = (uint)(raw & ~mask1 | (value << loc1) & mask1); }
}
public uint Item2
{
get { return (uint)(raw & mask2) >> loc2; }
set { raw = (uint)(raw & ~mask2 | (value << loc2) & mask2); }
}
public uint Item3
{
get { return (uint)((raw & mask3) >> loc3); }
set { raw = (uint)(raw & ~mask3 | (value << loc3) & mask3); }
}
}
Run Code Online (Sandbox Code Playgroud)
我发现自己对这些辅助函数非常满意:
uint SetBits(uint word, uint value, int pos, int size)
{
uint mask = ((((uint)1) << size) - 1) << pos;
word &= ~mask; //resettiamo le posizioni
word |= (value << pos) & mask;
return word;
}
uint ReadBits(uint word, int pos, int size)
{
uint mask = ((((uint)1) << size) - 1) << pos;
return (word & mask) >> pos;
}
Run Code Online (Sandbox Code Playgroud)
然后:
uint the_word;
public uint Itemx
{
get { return ReadBits(the_word, 5, 2); }
set { the_word = SetBits(the_word, value, 5, 2) }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
88203 次 |
| 最近记录: |