在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;
};

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

最佳答案 问题是你的数据在内存中的表现方式.

假设您有一个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”,这意味着你的“数字”变量在内存中的数字“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.
其他一切仍然是缓冲[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)
“array”指针的内容为“00 00 00 00 01 00 00 00”(指针为8字节),缓冲区指针为“02 00 00 00 03 00 00 00”.

这些是某种无效的指针,指出谁知道在哪里.这就是您尝试取消引用它们时出现访问冲突的原因.

点赞