在 C++/C# 之间的结构内传递 strings/arrays
Passing strings/arrays within structures between C++/C#
我正在将结构从 C# 传递到 C++。
C#代码:
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct Data
{
[MarshalAs(UnmanagedType.U4)]
public int number;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public int[] array;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
public string buffer;
}
C++代码:
struct Data
{
public:
int number;
int array[5];
char buffer[512];
//char *buffer;
};
以上方法效果很好。但是相反,如果我使用指针来处理 C++
中的数据,我会收到错误消息:
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory
struct Data
{
public:
int number;
int *array;
char *buffer;
};
为什么我不能在这里处理指针?
通过指针处理这种情况是否有利?
第一个结构有效,因为它在结构中分配了 array。
第二个是有问题的,因为它只在结构中分配了一个 int
指针和 char
指针(sizeof(void*)
取决于你的平台),而不是一个 int
数组。
如果你坚持使用指针,你必须自己分配和释放内存(即 new
和 delete[]
)。
问题在于您的数据在内存中的表示方式。
假设您有一个 c# 结构的实例,它编组到非托管代码甚至文件。
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct Data
{
[MarshalAs(UnmanagedType.U4)]
public int number = 5;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public int[] array = {0, 1, 2, 3, 4};
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
public string buffer = "Happy new Year";
}
据此,你的内存布局将是这样的(在十六进制视图中):
05 00 00 00 00 00 00 00
01 00 00 00 02 00 00 00
03 00 00 00 04 00 00 00
00 48 00 61 00 70 00 70
00 79 00 20 00 6E 00 65
00 77 00 20 00 59 00 65
00 61 00 72
这里我们有前四个字节“05 00 00 00”,这意味着 "number" 变量在内存中的数字“5”。 (请注意,这些字节的顺序是相反的,因为 Intel 架构是 LittleEndian,详情请参阅 Endiannes)
然后我们有接下来的五个整数“00 00 00 00”= 0,“01 00 00 00”= 1,“02 00 00 00”= 2,“03 00 00 00”= 3,“04” 00 00 00" = 4 对于名为 "array".
的数组
而字符串 "buffer" 表示如下:
"00 48" = H
"00 61" = a
"00 70" = p
"00 70" = p
"00 79" = y
"00 20" = <space>
"00 6E" = n
"00 65" = e
"00 77" = w
"00 20" = <space>
"00 59" = Y
"00 65" = e
"00 61" = a
"00 72" = r
.NET 总是使用 Unicode 来存储它的字符串变量。每个 Unicode 字符都有其双字节表示。
现在,对于这个 C++ 结构
struct Data
{
public:
int number;
int array[5];
char buffer[512];
//char *buffer;
};
sizeof(int) 是 4。因此变量 "number" = "05 00 00 00" 的内存内容是第 5 个。 array[0],array1,array[2],array[3],array[4] 布局在内存块上 "00 00 00 00" = 0, "01 00 00 00" = 1, " 02 00 00 00”= 2,“03 00 00 00”= 3,“04 00 00 00”= 4。
其他一切都保留给 buffer[512] 变量。但在c++中,sizeof(char) == 1。char数据类型通常用于表示旧的ASCII风格的文本,采用单字节编码。您应该改用 wchar_t,它非常适合 Unicode 编码。
现在让我们来看看
struct Data
{
public:
int number;
int *array;
char *buffer;
};
此结构将投影到与上述相同的内存布局上。
如果你 运行 在 32 位环境下 (win32)
"array" 指针的内容将为“00 00 00 00”(指针为 4 个字节)
"buffer" 指针将为“01 00 00 00”。
如果你运行在64位环境下(win64)
"array" 指针的内容将为“00 00 00 00 01 00 00 00”(指针为 8 个字节),缓冲区指针将为“02 00 00 00 03 00 00 00”。
这些是某种无效指针,指向谁知道在哪里。这就是为什么当您尝试取消引用它们时会出现访问冲突。
我正在将结构从 C# 传递到 C++。
C#代码:
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct Data
{
[MarshalAs(UnmanagedType.U4)]
public int number;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public int[] array;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
public string buffer;
}
C++代码:
struct Data
{
public:
int number;
int array[5];
char buffer[512];
//char *buffer;
};
以上方法效果很好。但是相反,如果我使用指针来处理 C++
中的数据,我会收到错误消息:
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory
struct Data
{
public:
int number;
int *array;
char *buffer;
};
为什么我不能在这里处理指针? 通过指针处理这种情况是否有利?
第一个结构有效,因为它在结构中分配了 array。
第二个是有问题的,因为它只在结构中分配了一个 int
指针和 char
指针(sizeof(void*)
取决于你的平台),而不是一个 int
数组。
如果你坚持使用指针,你必须自己分配和释放内存(即 new
和 delete[]
)。
问题在于您的数据在内存中的表示方式。
假设您有一个 c# 结构的实例,它编组到非托管代码甚至文件。
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct Data
{
[MarshalAs(UnmanagedType.U4)]
public int number = 5;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public int[] array = {0, 1, 2, 3, 4};
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
public string buffer = "Happy new Year";
}
据此,你的内存布局将是这样的(在十六进制视图中):
05 00 00 00 00 00 00 00
01 00 00 00 02 00 00 00
03 00 00 00 04 00 00 00
00 48 00 61 00 70 00 70
00 79 00 20 00 6E 00 65
00 77 00 20 00 59 00 65
00 61 00 72
这里我们有前四个字节“05 00 00 00”,这意味着 "number" 变量在内存中的数字“5”。 (请注意,这些字节的顺序是相反的,因为 Intel 架构是 LittleEndian,详情请参阅 Endiannes)
然后我们有接下来的五个整数“00 00 00 00”= 0,“01 00 00 00”= 1,“02 00 00 00”= 2,“03 00 00 00”= 3,“04” 00 00 00" = 4 对于名为 "array".
的数组而字符串 "buffer" 表示如下:
"00 48" = H
"00 61" = a
"00 70" = p
"00 70" = p
"00 79" = y
"00 20" = <space>
"00 6E" = n
"00 65" = e
"00 77" = w
"00 20" = <space>
"00 59" = Y
"00 65" = e
"00 61" = a
"00 72" = r
.NET 总是使用 Unicode 来存储它的字符串变量。每个 Unicode 字符都有其双字节表示。
现在,对于这个 C++ 结构
struct Data
{
public:
int number;
int array[5];
char buffer[512];
//char *buffer;
};
sizeof(int) 是 4。因此变量 "number" = "05 00 00 00" 的内存内容是第 5 个。 array[0],array1,array[2],array[3],array[4] 布局在内存块上 "00 00 00 00" = 0, "01 00 00 00" = 1, " 02 00 00 00”= 2,“03 00 00 00”= 3,“04 00 00 00”= 4。 其他一切都保留给 buffer[512] 变量。但在c++中,sizeof(char) == 1。char数据类型通常用于表示旧的ASCII风格的文本,采用单字节编码。您应该改用 wchar_t,它非常适合 Unicode 编码。
现在让我们来看看
struct Data
{
public:
int number;
int *array;
char *buffer;
};
此结构将投影到与上述相同的内存布局上。 如果你 运行 在 32 位环境下 (win32) "array" 指针的内容将为“00 00 00 00”(指针为 4 个字节) "buffer" 指针将为“01 00 00 00”。
如果你运行在64位环境下(win64) "array" 指针的内容将为“00 00 00 00 01 00 00 00”(指针为 8 个字节),缓冲区指针将为“02 00 00 00 03 00 00 00”。
这些是某种无效指针,指向谁知道在哪里。这就是为什么当您尝试取消引用它们时会出现访问冲突。