我现在从机器串口中返回一个Byte型数组Byte[] mbyte 其中有11个元素分别是:数据头  下位机  命令  状态  力  电压  电流    运行时间   数据长度  校验  数据尾
定义了一个对应的结构如下:
struct retu
        {
           public byte a;//数据头
            public byte b;//下位机地址
            public byte c;//命令
            public char d;//状态
            public float e;//力
            public float f;//电压
            public float g;//电流
            public float h;//运动时间
            public byte i;//数据长度
            public byte j;//数据尾
            //校验
            public byte Verify
            {
                get
                {
                    return (byte)(a ^ b ^ c ^ d ^ e ^ f ^ g ^ h ^ i);
                }
            }
        }
现在我需要将mbyte中的数按顺序付给结构retu。直接用循环赋值不行,结构中有char型和float型的元素。也不能进行数据类型转化,转换回来的值是错的。
在Delphi中的解决方法是:
将数组在内存中的首位置直接赋给结构的指针,这样两者中的元素就自动对应了,使用retu.e或retu.f等得出的值直接就是正确的数值不需要转换。
请问在C#中如何这样做?用指针么?怎么用?怎么解决类似问题?请说的详细点!谢谢各位!

解决方案 »

  1.   

    You may try this. If it doesn't work, try deleting "Pack=1", if it still goes wrong, come back to your manual.
        [StructLayout(LayoutKind.Sequential, Pack=1)]
        public struct retu
        {
            public byte a;//数据头 
            public byte b;//下位机地址 
            public byte c;//命令 
            public char d;//状态 
            public float e;//力 
            public float f;//电压 
            public float g;//电流 
            public float h;//运动时间 
            public byte i;//数据长度 
            public byte j;//数据尾 
        }        static retu GetRetu( byte[] mbyte )
            {
                if (Marshal.SizeOf(typeof(retu)) == mbyte.Length)              //<-- check their sizes do agree.
                {
                    GCHandle gch = GCHandle.Alloc(mbyte, GCHandleType.Pinned);
                    retu r = (retu)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(retu));
                    gch.Free();                return r;
                }
                else
                {
                    throw new Exception( "no luck, you need to check the manual for the retu struct" );
                }
            }
      

  2.   

    byte赋值到float没问题,直接赋.至于Char,你本来byte数组对应的是不是多位?(估计是一位吧)如果是一位,写成char=byte.ToString()[0].
      

  3.   

    先试试1楼的方法!
    请问1楼的:
    我直接使用你的方法:
    static retu GetRetu( byte[] mbyte )
            {
                if (Marshal.SizeOf(typeof(retu)) == mbyte.Length)              //<-- check their sizes do agree.
                {
                    GCHandle gch = GCHandle.Alloc(mbyte, GCHandleType.Pinned);
                    retu r = (retu)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(retu));
                    gch.Free();                return r;
                }
                else
                {
                    throw new Exception( "no luck, you need to check the manual for the retu struct" );
                }
            }
    黑体字部分会报错,提示“当前上下文中不存在名称“Marshal””或“找不到GCHandle,是否缺少USing引用”如果加上上面的[StructLayout(LayoutKind.Sequential, Pack = 1)]
    也提示StructLayout缺少using引用!
    请问怎么处理?
      

  4.   

    问题是if条件判断为false:
    if (Marshal.SizeOf(typeof(retu)) == mbyte.Length)   mbyte.Length=11   而   Marshal.SizeOf(typeof(retu)) =28Marshal.SizeOf(typeof(retu)) =28怎么出来的?
      

  5.   

    mbyte.Length=11如果是这样,那你的retu结构声明有错误。你可以自己数数看,
    一个byte:一个字节
    一个char:两个字节
    一个float:四个字节你得回头看说明书,是否用类似union的东西,否则
    11个字节的内存不足于提供retu结构需要的信息。
      

  6.   

    retu结构声明没有错!
    我把方法改了一下:
    static retu GetRetu( byte[] mbyte ) 
            { 
                if (Marshal.SizeOf(typeof(retu)) > mbyte.Length)              // <-- check their sizes do agree. 
                { 
                    GCHandle gch = GCHandle.Alloc(mbyte, GCHandleType.Pinned); 
                    retu r = (retu)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(retu)); 
                    gch.Free();                 return r; 
                } 
                else 
                { 
                    throw new Exception( "no luck, you need to check the manual for the retu struct" ); 
                } 
            } 
    把执行条件修改了一下,改成>,我想只要接受的数组长度小于结构大小就可以了。应为数组中这11个元素没有实际意义,关键是他们指向内存中位置的数据。这样执行下来能得出结果,但是结果是不是正确的,还没验证!所以,还不知道能不能这样做!
      

  7.   

    ...应为数组中这11个元素没有实际意义,关键是他们指向内存中位置的数据...No,
    Once it is a byte[11], it is no longer a pointer to your data in the memory.
    If you do so, you are populating the 'retu' structure with memory garbage.The sample story applies to 'memcpy'. You just can NOT use 11 bytes to fill a structure of more than 20 bytes.
      

  8.   

    建议:public interface Iretu 

              byte a { set; get; } //数据头 
                byte b { set; get; } //下位机地址 
                byte c { set; get; } //命令 
                char d { set; get; } //状态 
                float e { set; get; } //力 
                float f { set; get; } //电压 
                float g { set; get; } //电流 
                float h { set; get; } //运动时间 
                byte i { set; get; } //数据长度 
                byte j { set; get; } //数据尾 
                //校验 
                byte Verify { get;} 
    } public class retu:Iretu
    {
          ...
          public byte Verify 
          { 
              get 
              { 
                  return (byte)(a ^ b ^ c ^ d ^ e ^ f ^ g ^ h ^ i); 
              } 
          } }用类和数祖或Hashtable(也可以用泛型)可以很好地解决问题,对象就是指针...
      

  9.   

    C#里面的指针只能在加UNSAFE情况下使用
      

  10.   

    C#里面的指针只能在加UNSAFE情况下使用,此时就为非托管代码啦