在C ++/C#之间的结构内传递字符串/数组 [英] Passing strings/arrays within structures between C++/C#

查看:159
本文介绍了在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++中的数据,则会出现错误,如下所示:

未处理的异常:System.AccessViolationException:尝试读取或写入受保护的内存

struct Data
{
public:
    int number;
    int *array;
    char *buffer;
};

为什么我不能在这里处理指针? 通过指针处理这种情况有利吗?

解决方案

问题是您的数据如何在内存中表示.

假设您有一个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". (请注意,由于英特尔架构是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"对于名为"array"的数组,00"= 4.

字符串"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.因此,变量数字" ="05 00 00 00"(即数字5)的内存内容. array [0],array 1 ,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)下运行 数组"指针的内容将为"00 00 00 00"(指针为4个字节) 并且缓冲区"指针将为"01 00 00 00".

如果您在64位环境(win64)下运行 数组"指针的内容为"00 00 00 00 01 00 00 00"(指针为8个字节),缓冲区指针的内容为"02 00 00 00 03 00 00 00".

这些是某种无效的指针,指向谁知道哪里.这就是为什么当您尝试取消对它们的引用时会出现访问冲突.

I am passing a struct from C# to C++.

C# code:

[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++ code:

struct Data
{
public:
    int number;
    int array[5];
    char buffer[512];
    //char *buffer;
};

The above method works fine. But Instead if I use pointers to handle data in C++ I am getting error as:

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory

struct Data
{
public:
    int number;
    int *array;
    char *buffer;
};

Why cant I handle with pointers here? Is handling this case via pointers advantageous?

解决方案

The problem is how your data represented in memory.

Let's assume you have an instance of c# structure that marshals to unmanaged code or even file.

[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";
}

According to this, your memory layout will be like this (in hex-like view):

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

Here we have first four bytes "05 00 00 00", which means number "5" in memory for your "number" variable. (Notice that these bytes in reversed order because Intel architecture is LittleEndian, see Endiannes for details)

Then we have next five integers as "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 for array named "array".

And the string "buffer" represents like this:

"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

There is some trick that .NET always use Unicode to store it's string variables. Every Unicode character has it's two-byte representation.

Now, for this C++ struct

struct Data
{
public:
    int number;
    int array[5];
    char buffer[512];
    //char *buffer;
};

sizeof(int) is 4. So the content of memory for variable "number" = "05 00 00 00" which is number five. array[0],array1,array[2],array[3],array[4] lay out on memory blocks "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. Everything else remains to buffer[512] variable. But in c++, sizeof(char) == 1. The char data type usually used to represent old ASCII style text with a single byte encoding. You should use wchar_t instead which is perfectly fits for Unicode encodings.

Now let's take a look at

struct Data
{
public:
    int number;
    int *array;
    char *buffer;
};

This structure will be projected on the same memory layout as described above. If you're running under 32-bit environment (win32) the content of "array" pointer will be "00 00 00 00" (4 bytes for pointer) and "buffer" pointer will be "01 00 00 00".

If you're running under 64-bit environment (win64) the content of "array" pointer will be "00 00 00 00 01 00 00 00" (8 bytes for pointer) and buffer pointer will be "02 00 00 00 03 00 00 00".

These are some kind of invalid pointers which point who knows where. That's why you get Access Violation when you try to dereference them.

这篇关于在C ++/C#之间的结构内传递字符串/数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆