以前C++的代码,想移到C#上,请问在C#中怎么实现如下struct:
//C++ code
struct _cmdTag
{
    unsigned char cmd:4;
    unsigned char cmd_type:3;
    unsigned char active:1;
};vod SetCmdFrame(unsigned char* pBuf, unsigned char cmd, unsigned char cmd_type)
{
    _cmdTag *pFrame = (_cmdTag*)pBuf;
    pFrame->cmd = cmd;
    pFrame->cmd_type = cmd_type;
    pFrame->active = 0;    //主动或被动
    ...
}void IsCmdFrame(unsigned char* pBuf)
{
    _cmdTag *pFrame = (_cmdTag*)pBuf;
    if(pFrame->cmd == CMD_SEND_DATA)
    {
        ...
    }
    ...
}请问C#如何实现以上代码啊?

解决方案 »

  1.   

    ++ C#   
    char* string   
    传出的char* StringBuilder   
    short short   
    char byte   
    char[n] fixed byte[n]
    http://topic.csdn.net/u/20110124/18/b5ff89bd-b488-4e7e-bf87-926ab6251968.html
      

  2.   

    struct _cmdTag
    {
      byte cmd:4;
      byte char cmd_type:3;
      byte char active:1;
    };unsafe void SetCmdFrame(byte* pBuf, byte cmd, byte cmd_type)
    {
      _cmdTag* pFrame = (_cmdTag*)pBuf;
      pFrame->cmd = cmd;
      pFrame->cmd_type = cmd_type;
      pFrame->active = 0; //主动或被动
      ...
    }unsafe void IsCmdFrame(byte* pBuf)
    {
      _cmdTag* pFrame = (_cmdTag*)pBuf;
      if(pFrame->cmd == CMD_SEND_DATA)
      {
      ...
      }
      ...
    }
      

  3.   


    Ok,删除以前的东西重新用C#编程,
    那么C++实现的那个代码,
    请问用C#如何实现?
    谢谢!
      

  4.   

    非指针写法
    Class _cmdTag
    {
      public byte cmd;
      public byte cmd_type;
      public byte active;
      public static _cmdTag Convert(Byte[] b)
      {
          判断b
          _cmdTag c = new _cmdTag();
          c.cmd = b[0];
          c.cmd_type = b[1];
          c.active = b[2];
          return c;
      }
    };void SetCmdFrame(byte[] pBuf, byte cmd, byte cmd_type)
    {
      _cmdTag pFrame = _cmdTag.Convert(pBuf);
      pFrame.cmd = cmd;
      pFrame.cmd_type = cmd_type;
      pFrame.active = 0; //主动或被动
      ...
    }void IsCmdFrame(byte[] pBuf)
    {
      _cmdTag pFrame = _cmdTag.Convert(pBuf);
      if(pFrame.cmd == CMD_SEND_DATA)
      {
      ...
      }
      ...
    }
      

  5.   

    凡是把下面代码:
    //C++ code
    struct _cmdTag
    {
      unsigned char cmd:4;
      unsigned char cmd_type:3;
      unsigned char active:1;
    };
     理解为:
    struct _cmdTag
    {
      unsigned char cmd[4];
      unsigned char cmd_type[3];
      unsigned char active[1];
    };
    或者:
    struct _cmdTag
    {
      unsigned char[4] cmd;
      unsigned char[3] cmd_type;
      unsigned char[1] active;
    };请,先弄明白C++的“位域”,
    谢谢!
      

  6.   

    看来这个小问题,
    竟然遇到大麻烦了,
    老板让我们转到C#,
    看来C#并不能完成C++所能完成的全部功能啊。
      

  7.   

    从应用的层面来说,一个语言能够实现的功能,几乎都能够用其它任何一种合格的语言来实现,其区别只有编码效率和运行效率的区别。就像SP1234说的,不要纠结这些细节,用C#重写一次就行了
      

  8.   

    帮你查到一篇,是这个
    http://topic.csdn.net/t/20030531/22/1860471.html
      

  9.   

    微软不是号称C#无所不能吗,
    能完成C++所有的功能吗?
    晕,到底转向C#可以吗?
      

  10.   

    udp组包的时候用过,原来这个叫位域啊
    上面这个帖子牛,想到枚举
      

  11.   


    谢谢!那个帖子的问题与我这个问题有相似的地方,
    但是它那是用C#的枚举解决问题,
    但这是不行的,例如:
    struct _cmdTag
    {
      unsigned int cmd:4;
      unsigned int active:1; 
      unsigned int frame_len:27;
    };
    就没法解决,因为frame_len是表示27bit的整数值。
       
      

  12.   

    以前用c组过mac帧,的确比c#方便很多,后来再做都是用整形和字符串组byte,没想到什么好办法
      

  13.   

    脑筋不要这么死板好不好,c++有位域,c#就一定要支持?那要让你把C++的代码给改成perl的,你不是要抓狂了。
    你那个结构用C#写成下面这样,浪费一点空间不就完了,active的类型也可以改成bool。移植程序嘛,灵活一点。要是什么都完全一样,就用不着移植了struct _cmdTag
    {
      unsigned char cmd;
      unsigned char cmd_type;
      unsigned char active;
    };
      

  14.   


    朋友,你没有写过类似的东西,可能没法理解
    例如
    void compose(char* buffer)
    {
        //buffer 是需要out的数据帧 函数内组包    //ether头 结构体
        ether_header* eh;
        //arp头 结构体
        arp_header* ah;    eh = (etherheader*)buffer;
         ah = (arp_header*)(buffer+sizeof(ether_header)) ;    eh.dmac =...
        ...
        
        ah.targetip = ...    这样,在数据帧的各部分结构体的数据赋值完毕之后,buffer也同时填充完毕了
        也就是说,如果用了char,那么在buffer中就明显存在了问题,因为原来是1bit的数据你填充了8bit!!!
    }这个问题要从内存角度去理解,个人在C#还没有发现可以达到这种目的的方法,当然可能是我才疏学浅
      

  15.   

    楼主啊,不管数据帧内各部分是什么,最后组包完毕总是byte的整数倍
    所以如果没什么好办法的话,用char或者其他类型作为结构体的成员类型,敷值完毕以后自己计算byte很傻,不过能做出来C#有自己的优势,不过底层的东西,还是C比较方便
      

  16.   


    不知道这样行不
     class Program
        {
            static void Main(string[] args)
            {
                CmdTag ct = new CmdTag(25);
                Console.WriteLine(string.Format("cmd:{0} cmdType:{1} active:{2}", ct["cmd"], ct["cmd_type"],ct["active"]));
                ct["cmd"] = 3;
                Console.WriteLine(string.Format("cmd:{0} cmdType:{1} active:{2}", ct["cmd"], ct["cmd_type"], ct["active"]));
                ct["cmd_type"] = 6;
                Console.WriteLine(string.Format("cmd:{0} cmdType:{1} active:{2}", ct["cmd"], ct["cmd_type"], ct["active"]));
                ct["active"] = 1;
                Console.WriteLine(string.Format("cmd:{0} cmdType:{1} active:{2}", ct["cmd"], ct["cmd_type"], ct["active"]));
                CmdTag ct1 = (CmdTag)3;            Console.WriteLine(string.Format("cmd:{0} cmdType:{1} active:{2}", ct1["cmd"], ct1["cmd_type"], ct1["active"]));
                Console.ReadLine();        }
        }
        class CmdTag 
        {
            private byte _v;        //构造函数
            public CmdTag() { }
            public CmdTag(byte v) 
            {
                _v = v;
            }        //强制运算符的重载,将byte转换为CmdTag类型
            public static explicit operator CmdTag(byte b)
            {
                return new CmdTag(b);
            }        //索引器
            public byte this[string str] 
            {
                //获取字段值
                get 
                {
                    if (str == "cmd") return (byte)(_v >> 4);
                    if (str == "cmd_type") return (byte)((_v & 0xf) >> 1);
                    if (str == "active") return (byte)(_v & 0x01);
                    throw new Exception(string.Format("不存在字段:{0}", str));
                }
                //设置字段值
                set 
                {
                    if (str == "cmd") _v = (byte)((_v&0xf)|(value<<4));
                        else if (str == "cmd_type") _v =(byte)((_v&0xf1)|(value<<1));
                        else if (str == "active") _v = (byte)((_v&0xfe)|value);
                        else throw new Exception(string.Format("不存在字段:{0}",str));
                }
            }
        }
      

  17.   

    抱歉有点错误if (str == "cmd") _v = (byte)((_v&0xf)|(value<<4));
                    else if (str == "cmd_type") _v = (byte)((_v & 0xf1) | ((value << 1) & 0xe));
                    else if (str == "active") _v = (byte)((_v&0xfe)|(value&0x1));
                    else throw new Exception(string.Format("不存在字段:{0}",str));
      

  18.   

    楼上那个写得很好了,我再班门弄斧一下,哈哈
    struct _cmdTag
            {
                public byte b;
                public byte cmd()
                {
                    return (byte)(((byte)(b << 4)) >> 4);
                }
                public byte cmd_type()
                {
                    return (byte)(((byte)(b << 1)) >> 5);
                }
                public byte active()
                {
                    return ((byte)(b >> 7));
                }
            }
            unsafe static void Main(string[] args)
            {
                byte* f = stackalloc byte[10];
                *f = 248;
                _cmdTag* d = (_cmdTag*)f;
                Console.WriteLine(d->cmd());
                Console.WriteLine(d->cmd_type());
                Console.WriteLine(d->active());
                Console.ReadLine();
            }
      

  19.   

    C#肯定不能直接提供你想要的这种功能,你需要像后面几位回复写的那样,写一些把结构体转换成字符流的代码。肯定要比C++麻烦,这是语言本身决定了的。还是那句话,要是把这段代码转换成perl,你怎么办?多想办法,多绕弯子嘛,移植的工作量就是在这些东西方面了
      

  20.   

    try like thisusing 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;
        }
      }
    }
      

  21.   


    你说得倒是好,
    改下代码就行吗?
    把所有设备的代码都改变吗?
    那么请说服大家把TCP等等协议都改变吧!
      

  22.   

    这样的贸然转型确实很危险,以LZ目前对C#的了解,即使转过来,项目或产品的质量也是无法保证的,尤其是涉及这种底层细节,需要有足够经验积累才可以。如果老板非要转的话,LZ可以建议先把一些简单、C#有优势的部分做移植
      

  23.   

    真晕啊,
    问了个位域问题,
    硬是让一帮人说C++故意执拗于性能,
    故意钻牛角之类显示自己理论多高的样子,
    说白了,做应用软件的人,
    很难理解底层为什么要这么做,
    真是不做一行,不懂一行啊,
    希望那些没有做过底层的,
    不要再以此来讥讽了,
    做C++的并不是为显摆才让代码那样子,
    我也知道了C#的局限,
    所以转入C#也会深重考虑了。
      

  24.   

    _cmdTag c = new _cmdTag();
      c.cmd = b[0];
      c.cmd_type = b[1];
      c.active = b[2];
      return c;
      }
    };
      

  25.   

    To ChinaOS
    非托管 转 托管的时候并不一定要把代码全部重写,也可以试着将非托管的部分封装成dll,给托管代码调用
    像bitfield 及 union等最好能通过接口封装掉,不是说C#不能调,而是降低调用的麻烦程度,凡事有个度,具体事情具体衡量。PS:某些人回答问题最好能看清楚别人问的问题是什么才回答,而不是一上来就否定人家,给出的建议也没什么建树,不知所云,不止在一个帖子里看到这样的回答,忍不住多嘴一句。
      

  26.   

    不懂位域是什么,但如果是我来做这个程序,可能会用两种办法,一是对原始的数据直接进行位运算获取或设置相应位的值,二是使用System.Collections.Specialized.BitVector32这个结构完全位的运算。BitVector32 cmd = new BitVector32();
    BitVector32.Section sectCmd = BitVector32.CreateSection(4);
    BitVector32.Section sectCmdType = BitVector32.CreateSection(3, sectCmd);
    BitVector32.Section sectActive = BitVector32.CreateSection(1, sectCmdType);cmd[sectCmd] = 2;
    cmd[sectCmdType] = 1;代码没有测试过,随手敲的,希望对你有帮助。
      

  27.   


    对,您这话在理,
    我从C++刚转到C#(老板让的),
    对C#比较茫然(当然学得还是比较快的,看了一个星期的C#电子书),
    只是对位域感到有些棘手,
    迫切希望能得到有这方面经验的帮助,
    希望回答问题前,确实要搞清楚别人在问什么,
    这样对自己也是一次帮助。
      

  28.   

    哥们,首先感谢你这个问题,受这个问题的启发,我把原来一个程序中7-bit编解码的部分进行了一次改进。不过你在已有C/C++的基础上,看了一星期C#了,到论坛问这个问题,其实学的是相当的“不快”啊。
    在我们公司招聘人的时候,不会对人员长期使用的语言有严格的限制,因为是小公司。但不论C#程序员将原有程序改为C++,还是C++程序员将原有程序改为C#,不管有没有学过另一个语言,一个东西的移植都不会因为跨语言而卡壳。卡壳只会发生在语言层面之外的思路上。
      

  29.   


    也感谢您鼎力帮助,
    确实,语言的东西,关键要看怎么用它,
    我们公司老板看到C#做界面快,
    也就希望我们用它,
    其实底层的东西,
    还是C/C++合适,
    当然,仁者见仁智者见智了。
      

  30.   

    如你所说,没有直接支持的方法,需要转一下。用属性也不错。//C++ code
    struct _cmdTag
    {
      unsigned char cmd:4;
      unsigned char cmd_type:3;
      unsigned char active:1;
    };vod SetCmdFrame(unsigned char* pBuf, unsigned char cmd, unsigned char cmd_type)
    {
      _cmdTag *pFrame = (_cmdTag*)pBuf;
      pFrame->cmd = cmd;
      pFrame->cmd_type = cmd_type;
      pFrame->active = 0; //主动或被动
      ...
    }void IsCmdFrame(unsigned char* pBuf)
    {
      _cmdTag *pFrame = (_cmdTag*)pBuf;
      if(pFrame->cmd == CMD_SEND_DATA)
      {
      ...
      }
      ...
    }public struct _cmdTag
    {
        private byte data;
        public byte cmd
        {
            get { return cmd & 15; }
            set { data |= value; }
        }
        public byte cmd_type
        {
            get { return cmd >> 4 & 7; }
            set { data |= value << 4; }
        }
        public byte active
        {
            get { return cmd >> 7; }
            set { data |= value << 7; }
        }
        //直接赋值
        public byte Data
        {
            get { return data; }
            set { data = value; }
        }
    }
      

  31.   


    using System.Runtime.InteropServices;   [StructLayout(LayoutKind.Explicit)]
        public struct _cmdTag
        {
            [FieldOffset(0)]
            public byte cmd;
            [FieldOffset(4)]
            public byte cmd_type;
            [FieldOffset(7)]
            public byte active;
        }
      

  32.   

    lsFieldOffset
    都到字节了,他要的是位。
      

  33.   

    这节过得 走神得厉害了 
    位操作 << >> 不就得了 何必纠结于 语言 语法