C#中实现位域功能

发布时间:2024年01月09日

此需求多用于使用C#调用C语言的库,由于C语言写的程序为了节省内存,通常会使用到位域这种数据结构,而C#中没有对应的位域结构,因此需要用其他的语法模拟出位域的效果。

位域

位段(或称“位域”,Bit field)为一种数据结构,可以把数据以的形式紧凑的储存,并允许程序员对此结构的位进行操作。相邻的两个位域如果基类型(underlying type)的长度相同,在后的位域适合当前内存分配单元且没有跨内存分配边界,那么这两个位域分配到同一个(1、2或4字节的)分配单元。可以通俗理解为:具有相同的基类型(underlying type)长度的相邻位域尽量装入基类型的同一个对象,如果装得下的话。

上面是一个C语言的头文件声明,此次的需要就是要用C#去建立一个结构体能与C的结构体对应上。我们先看实现。

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public class Frame
        {
        
            public UInt64 Timestamp;     // us

            public UInt32 Id;


            private UInt16 Flags;//Flags用于存放下列值,并用C#属性来实现位域的功能。

            //属性用于访问位域
            public UInt16 SendType  // 仅发送有效, 接收为0, 0:正常发送, 1:单次发送 2:自发自收
            {
                get { return (ushort)(Flags & (0x0003)); }
                set { Flags = (ushort)((Flags & ~0x0003) | (value & 0x0003)); }
            }
            public UInt16 Tx           // 1:tx 2:rx
            {
                get { return (ushort)((Flags & (0x0004)) >> 2); }
                set { Flags = (ushort)((Flags & ~0x0004) | ((value << 2) & 0x0004)); }
            }
            public UInt16 Echo
            {
                get { return (ushort)((Flags & (0x0008)) >> 3); }
                set { Flags = (ushort)((Flags & ~0x0008) | ((value << 3) & 0x0008)); }
            }
            public UInt16 Fd           // 1:canfd 2:can
            {
                get { return (ushort)((Flags & (0x0010)) >> 4); }
                set { Flags = (ushort)((Flags & ~0x0010) | ((value << 4) & 0x0010)); }
            }
            public UInt16 Rtr          // 1:remote 0:data frame
            {
                get { return (ushort)((Flags & (0x0020)) >> 5); }
                set { Flags = (ushort)((Flags & ~0x0020) | ((value << 5) & 0x0020)); }
            }
            public UInt16 Ext         // 1:extend 0:standard
            {
                get { return (ushort)((Flags & (0x0040)) >> 6); }
                set { Flags = (ushort)((Flags & ~0x0040) | ((value << 6) & 0x0064)); }
            }
            public UInt16 Err          // 1:error frame 0:normal frame;
            {
                get { return (ushort)((Flags & (0x080)) >> 7); }
                set { Flags = (ushort)((Flags & ~0x0009) | ((value << 7) & 0x0009)); }
            }
            public UInt16 Brs          // 1:canfd加速 0:不加速
            {
                get { return (ushort)((Flags & (0x0100)) >> 8); }
                set { Flags = (ushort)((Flags & ~0x000A) | ((value << 8) & 0x000A)); }
            }
            public UInt16 Esi          // 1:被动错误 0:主动错误
            {
                get { return (ushort)((Flags & (0x0200)) >> 9); }
                set { Flags = (ushort)((Flags & ~0x000B) | ((value << 9) & 0x000B)); }
            }
            public UInt16 Reserved     // 保留
            {
                get { return (ushort)((Flags & (0x7C00)) >> 10); }
                set { Flags = (ushort)((Flags & ~0x7C00) | ((value << 10) & 0x7C00)); }
            }
            public UInt16 Trigger      // 触发位
            {
                get { return (ushort)((Flags & (0x8000)) >> 15); }
                set { Flags = (ushort)((Flags & ~0x8000) | ((value << 15) & 0x8000)); }
            }


            public byte Channel;        // 通道号, 若为-1, 代表该报文是发送给所有的通道



            public byte Len;

 
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] Data;

          


        }

属性

属性(Property)?是类,结构,接口的成员。提供一个操作其他私有(private)字段的渠道,为了防止用户篡改结构,类中的字段。用于可以自定义get(),set()访问器中操作字段的方法。

此处使用了C#的属性语法,新建一个Flags的16位整型变量用于存放需要使用位域操作的数据,然后新建了不同的属性语法中来访问Flags中对应的各自数据。此处get()访问器中使用了&的位运算符,以求取得各自的有效数据。

以SendType为例,

占16位中的2个位,并且处于最低的两个位,因此有效位为二进制表达为b0000000000000011转成16进制为0x0003.因此用flags按位与0x0003.便能获取flags中最低两个位的数据,然后再用(ushort)强转成16位整型。


在属性中,当我们需要改变类/结构中某个私有字段时,使用set访问器。

(Flags & ~0x0003):首先用Flags与上求反的0x0003,目的是储存数据的无关部分。
(value & 0x0003):用设定值value与上0x0003,得到数据有效部分.
然后用按位或(|),把两个部分的数据叠加起来。


到这里,我们便完成了对其中某一个数据存与取,然后以此类推,就能够完成整个16位整型中所有数据的存取操作。

文章来源:https://blog.csdn.net/AmiensLiew/article/details/135449352
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。