【发布时间】:2021-06-17 22:47:33
【问题描述】:
我试图从 c# 对 c++ dll 的调用返回一个结构,但我得到了一些我不理解的复杂和不良行为。如果我的结构包含一个构造函数,我在返回它时会遇到内存访问冲突,如果它小于 12 个字节。如果大一点就没有问题。如果我删除构造函数,它适用于所有尺寸。我想这可能与我的调用是 c 风格有关,但我找不到有关此的信息。因此,如果有人可以解释或指出我正在发生的事情的一个好的方向,将不胜感激。以下是有效和无效的代码示例:
有效的代码
C++ 端标题:
#define DLL_API __declspec(dllexport)
struct Struct4Byte
{
int x1;
};
struct Struct12Byte
{
int x1;
int x2;
int x3;
Struct12Byte() { x1 = 0; x2 = 1; x3 = 2; }
};
#ifdef __cplusplus
extern "C" {
#endif
DLL_API Struct4Byte Function4Byte(int x);
DLL_API Struct12Byte Function12Byte(int x);
#ifdef __cplusplus
}
#endif
C++ 文件:
Struct4Byte Function4Byte(int x)
{
Struct4Byte output;
output.x1 = 1 + x;
return output;
}
Struct12Byte Function12Byte(int x)
{
Struct12Byte output;
output.x1 = 1 + x;
output.x2 = 2 + x;
output.x3 = 3 + x;
return output;
}
在调用方 (C#) 我这样做:
[StructLayout(LayoutKind.Sequential)]
internal struct Struct4Byte
{
public int x1;
}
[StructLayout(LayoutKind.Sequential)]
internal struct Struct12Byte
{
public int x1;
public int x2;
public int x3;
}
class Program
{
static void Main(string[] args)
{
Struct4Byte result1 = Function4Byte(3);
Struct12Byte result2 = Function12Byte(3);
}
[DllImport(@"PInvokeCheck.dll")]
internal static extern Struct4Byte Function4Byte(int x);
[DllImport(@"PInvokeCheck.dll")]
internal static extern Struct12Byte Function12Byte(int x);
}
无效的代码
如果我现在在头文件中将 Struct4Byte 的定义更改为:
struct Struct4Byte
{
int x1;
Struct4Byte(){ x1 = 0; }
};
然后我得到内存访问冲突。
我注意到了一些可能感兴趣的东西。问题已经在调用 Function4Byte 时出现了。在函数中放置一个断点并查看 x(我在下面再次放置了函数)表明 x 得到了一些随机值。
Struct4Byte Function4Byte(int x)
{
Struct4Byte output;
output.x1 = 1 + x;
return output;
}
【问题讨论】:
-
CallingConvention应该是Cdecl吧?那么填充呢,x64 会填充到 8 个字节 -
这似乎没有任何效果。但我不是 100% 确定如何进行填充。我在 c# 中使用了
[StructLayout(LayoutKind.Sequential, Pack = 8)],我也在 c++ 中尝试了#pragma pack(8)。但没有改善。 -
奇怪的是,对于具有两个 int 成员(所以 8 个字节)但不是 12 个字节或更大的结构,我也有同样的问题。我想我可以通过不包含任何构造函数或添加一些额外的数据来解决这个问题。但是,我真的不知道问题是否已解决,或者它是否只是偶然发生的。
-
不返回结构体,而是将结构体的引用作为参数传递呢? Marshaling Classes, Structures, and Unions
-
这显然是一个选项,我已经为我返回的大部分数据做了什么。但我主要关心的不是让它工作,而是理解它为什么不工作。否则,当我以其他方式返回我的结构时,这也可能是一个问题。