在C++/C#之间的结构中传递字符串/数组
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++
中的数据,我会得到错误:
未处理的异常: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",这意味着内存中"数字"变量的数字"5"。(请注意,这些字节的顺序相反,因为Intel体系结构是LittleEndian,有关详细信息,请参阅Endiannes)
对于名为"array"的数组,接下来有五个整数,分别为"00 00 00 00"=0、"01 00 00"=1、"02 00 00"=2、"03 00 00"=3、"04 00 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。因此,变量"number"的内存内容="05 00 00 00",即数字5。array[0]、array1、array[2]、array[3]、array[4]在内存块上布局"00 00 00 00"=0、"01 00 00"=1、"02 00 00"=2、"03 00 00"=3、"04 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)下运行"数组"指针的内容将为"00 00 00 01 00 00 00"(指针为8个字节),缓冲区指针将为"02 00 00 03 00 00"。
这些是某种无效的指针,指向谁知道在哪里。这就是为什么当你试图取消引用它们时会出现访问违规的原因。
第一个结构之所以有效,是因为它在结构中分配数组。第二个是有问题的,因为它只在结构中分配int
指针和char
指针(sizeof(void*)
取决于您的平台),而不是int
数组。如果你坚持使用指针,你必须自己分配和释放内存(即new
和delete[]
)。
- 将C#字符串数组传递给C++
- 如何为 C 型字符串数组编写 getter 和 setter?
- 有没有办法使用 strcpy 将字符串数组复制到另一个字符串或其他数组中?
- 尝试将 c 字符串数组与分隔符连接起来
- 将字符串数组传递给接受常量字符**的函数
- 返回 C++ 中的字符串数组
- 如何从COM模块中的函数返回字符串数组?
- 无法将字符串数组声明为类成员而不是字符 (C++)
- 删除字符串数组
- 如何将字符串数组返回到 java JNI
- 将字符串数组作为函数参数传递
- C++将字符串数组的元素存储到变量中
- 循环访问还包含未使用元素的字符串数组
- 字符串数组上的 sizeof 运算符以 C++ 为单位给出不同的输出
- 乘以字符串/数组和全局数组
- 递归二进制搜索与字符串数组
- 如何初始化一个标准::字符串数组?
- 无法在声明时使用初始值设定项列表初始化常量字符*/字符串数组的向量
- C++字符串数组的动态向量
- 给定一个等长字符串数组