无法将固定大小的字节数组从结构复制到 C# 结构中的另一个数组

Posted

技术标签:

【中文标题】无法将固定大小的字节数组从结构复制到 C# 结构中的另一个数组【英文标题】:Can't copy a fixed-size byte array from a struct to another array in a struct in C# 【发布时间】:2020-08-20 02:02:23 【问题描述】:

使用NetworkInfo2SecurityParameter 函数,我试图将固定大小的缓冲区unkRandomLdnNetworkInfo 结构中的NetworkInfo 结构复制到SecurityParameter 结构的缓冲区。

基本上我正在制作一种转换这两种类型的方法,并且我想将这两个数组复制到另一个数组。此代码具有所有相关的结构。

Buffer.MemoryCopy() 函数发生错误。错误是“您不能使用包含在未固定表达式中的固定大小缓冲区。尝试使用 'fixed' 语句”

unsafe void NetworkInfo2SecurityParameter(NetworkInfo info, out SecurityParameter output)

    output = new SecurityParameter();
    output.sessionId = info.networkId.sessionId;
    Buffer.MemoryCopy(output.unkRandom, info.ldn.unkRandom, 16, 16);


struct SecurityParameter 
    public unsafe fixed byte unkRandom[16];// = new byte[16];
    public SessionId sessionId;
;

struct NetworkInfo : /sf::/LargeData 
    public NetworkId networkId;
    public CommonNetworkInfo common;
    public LdnNetworkInfo ldn;
;

struct LdnNetworkInfo 
    public unsafe fixed byte unkRandom[16];// = new byte[16];
    public ushort securityMode;
    public byte stationAcceptPolicy;
    public unsafe fixed byte _unk1[3];// = new byte[3];
    public byte nodeCountMax;
    public byte nodeCount;
    //TODO non primitive array,,
    private unsafe fixed byte _nodes[sizeof(NodeInfo)*NodeCountMax]; //Needs to be fixed array, and needs to be casted to NodeInfo span, so thats why its size is this
    public unsafe fixed Span<NodeInfo> nodes => MemoryMarshal.Cast<byte, NodeInfo>(MemoryMarshal.CreateSpan(ref _nodes[0], 128));
    public ushort _unk2;
    public ushort advertiseDataSize;
    public unsafe fixed byte advertiseData[AdvertiseDataSizeMax];// = new byte[AdvertiseDataSizeMax];
    public unsafe fixed byte _unk3[148];// = new byte[148];
;

【问题讨论】:

错误是什么? 您不能使用包含在未固定表达式中的固定大小的缓冲区。尝试使用“固定”语句 嗯,显而易见的问题是,您是否尝试过使用fixed 语句? 如果数组只有 16 个字节,你能把一个指向数组的指针转换成一个 int64 指针,然后复制成两个 64 位的块吗? @HereticMonkey 在哪里? 【参考方案1】:

struct 是可赋值的,就像任何原语一样。毫无疑问,比Buffer.MemoryCopy() 更快的是:

public unsafe struct FixedSizeBufferWrapper

    public unsafe fixed byte unkRandom[16];


unsafe 

    fixed (byte* firstStruct = somewhere.securityParameter, otherStruct = somewhereElse.ldnNetworkInfo )
    
        //one assignment blits all contents
        *((FixedSizeBufferWrapper*)firstStruct.unkRandom) =
        *((FixedSizeBufferWrapper*)otherStruct.unkRandom);
    

我们将每个原始结构中的缓冲区转换为包装指针类型并取消引用每个指针,以便我们可以将一个分配给另一个;无法直接分配fixed 缓冲区。

我们必须在 fixed 语句之外进行转换,因为(至少在我的 C# 版本中)我们不允许在 fixed(...) 内进行转换,并且我们不能分配除原始类型以外的任何内容(通常是 byte[])作为缓冲区类型。包装器结构的存在纯粹是为了这种强制转换/分配。

【讨论】:

【参考方案2】:

用这种方法修复它:我创建了一个名为 ret 的新变量,我确实将数据复制到该变量,然后我将 ret 分配给了输出。

unsafe void NetworkInfo2SecurityParameter(NetworkInfo info, out SecurityParameter output)
        
            var ret = new SecurityParameter();
            output.sessionId = info.networkId.sessionId;
            Buffer.MemoryCopy(ret.unkRandom, info.ldn.unkRandom, 16, 16);
            output = ret;
        

【讨论】:

以上是关于无法将固定大小的字节数组从结构复制到 C# 结构中的另一个数组的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中尽可能快地将数组复制到结构数组

直接将 C++ 浮点数组成员编组到 C#,无需复制

C# 中具有固定大小数组的连续分层结构内存?

Cuda 高效地从字节数组复制到不同大小的共享内存元素

将字节缓冲区内容复制到结构中

将结构数组从 C# 传递到 C++