C# 模仿C++;C中带并集的嵌套结构#
我知道这个问题以前已经被问过很多次了,我试着把前面的问题通读一遍,但运气不好 我尝试将下面的C++结构转换成C语言,用于socket通信。C# 模仿C++;C中带并集的嵌套结构#,c#,c++,struct,C#,C++,Struct,我知道这个问题以前已经被问过很多次了,我试着把前面的问题通读一遍,但运气不好 我尝试将下面的C++结构转换成C语言,用于socket通信。 enum class packet_type { read_mem, get_base_addr, get_pid, completed }; struct copy_mem { unsigned int dest_process_id; unsigned long long dest_address;
enum class packet_type
{
read_mem,
get_base_addr,
get_pid,
completed
};
struct copy_mem
{
unsigned int dest_process_id;
unsigned long long dest_address;
unsigned int src_process_id;
unsigned long long src_address;
unsigned int size;
};
struct get_base_addr
{
unsigned int process_id;
};
struct get_pid
{
size_t len;
wchar_t name[256];
};
struct completed
{
unsigned long long result;
};
struct PacketHeader
{
//uint32_t magic;
packet_type type;
};
struct Packet
{
PacketHeader header;
union
{
copy_mem copy_memory;
get_base_addr get_base_address;
get_pid get_pid;
completed completed;
} data;
};
这是我目前的C#实现
public enum PacketType
{
read_mem = 0,
get_base_addr = 1,
get_pid = 2,
completed = 3
}
[StructLayout(LayoutKind.Sequential)]
public struct PacketHeader
{
public PacketType type;
}
[StructLayout(LayoutKind.Sequential)]
public struct get_base_addr
{
uint process_id;
};
[StructLayout(LayoutKind.Sequential)]
public struct get_pid
{
public ulong len;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string name;
}
[StructLayout(LayoutKind.Sequential)]
public struct copy_mem
{
public uint dest_process_id;
public ulong dest_address;
public uint src_process_id;
public ulong src_address;
public uint size;
}
[StructLayout(LayoutKind.Sequential)]
public struct completed
{
public ulong result;
};
[StructLayout(LayoutKind.Explicit, Pack = 0, CharSet = CharSet.Unicode)]
public struct Packet
{
[FieldOffset(0)] //
public PacketHeader header;
[FieldOffset(4)]
public copy_mem CopyMem; //28
[FieldOffset(32)]
public get_base_addr GetBaseAddress;
[FieldOffset(36)]
public get_pid GetPid;
[FieldOffset(300)]
public completed Completed;
}
然后,我使用此方法将结构转换为用于套接字传输的字节数组:
public static byte[] RawSerialize(T item)
{
int rawSize = Marshal.SizeOf(typeof(T));
IntPtr buffer = Marshal.AllocHGlobal(rawSize);
var a = Marshal.SizeOf(item);
var b = Marshal.SizeOf(buffer);
Marshal.StructureToPtr(item, buffer, false);
byte[] rawData = new byte[rawSize];
Marshal.Copy(buffer, rawData, 0, rawSize);
Marshal.FreeHGlobal(buffer);
return rawData;
}
问题是
var a=Marshal.SizeOf(项目)
报告的大小为312
,但在C++中执行sizeof(Packet)
时,实际的结构应该是528
字节。您的假设似乎是错误的。首先,wchar\u t
类型在不同的机器上可能具有不同的长度。在我的x64 Linux机器上,它是4个字节——这就使得get_pid
a1032
字节大小的结构。您可能对使用char16\u t
或char32\u t
类型感兴趣(请参见示例)
由于数据包
中的联合
与所有字段重叠,这也使得数据包
成为一个1040
字节大小的结构:4
字节用于PacketHeader
,1032
字节用于get\u pid
,这是迄今为止最长的结构,并且4
字节用于填充。遗憾的是,填充是特定于平台的
为了摆脱C/C++编译器中的填充,您需要使用诸如GCC的\uuuu属性(packed))
或Visual C++的\pragma pack(1)
(参见示例SO答案)之类的属性
小心,C中的字段偏移也是错误的:除了标题,代码< >包<代码>中的所有字段偏移必须是代码> [FieldS偏移(4)] < /C> >因为在C++中,它是<代码>联合< <代码>,开始于字节<代码> 4代码>(假设为零填充)。 对于可移植性,还要注意
无符号long-long
也是特定于平台的,唯一的保证是至少64位长。如果您恰好需要64位,则可能需要使用uint64\u t
(参见示例)
以下是我用来确定大小的代码(Linux x64,GCC 9.3):
intmain(){
STD::C++Stutt中的所有字段都共享相同的存储空间,在C++中如何实现这一点?我不知道,这就是我为什么来这里的原因:它们有相同的偏移量。EnUM类也不是跨语言兼容的。网络协议明确地定义了字段大小。谢谢你们的详细响应。如果我改变了<代码>字段偏移< /COD>所有的S在数据包
中,我在运行应用程序时得到了这个消息-数据包无效…因为它在偏移量4处包含一个对象字段,该字段与非对象字段不正确对齐或重叠。
罪魁祸首是get_pid
结构的名称
字段,我能说的就这么多。
packet_type: 4
copy_mem: 40
get_base_addr: 4
get_pid: 1032
completed: 8
PacketHeader: 4
Packet: 1040
wchar_t: 4
packet_type: 4
copy_mem: 28
get_base_addr: 4
get_pid: 1032
completed: 8
PacketHeader: 4
Packet: 1036
wchar_t: 4
Unhandled exception. System.TypeLoadException: Could not load type 'Packet' from assembly 'StructSize, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 4 that is incorrectly aligned or overlapped by a non-object field.