PInvoke中x64 C中的内存地址重叠

时间:2017-01-12 00:09:06

标签: c# c pinvoke

我们有一个PInvoke如下:

[DllImport(DllName, EntryPoint = "ExternalName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ExternalFunction(IntPtr state, IntPtr inputData, int inputIndex, int inputLength, int tailLength);

使用C声明如下:

void * __cdecl ExernalName(void* state, void* inputData, int32_t inputIndex, int32_t inputLength, int32_t tailLength);

当以x86运行.NET应用程序时,它可以正常工作。但是,当在x64机器上的AnyCPU中运行时,函数参数的内存地址关闭。

例如,假设state = 1,inputData = 2,inputIndex = 3,inputLength = 4.State和InputData都是void *,因此它们应该是8个字节长,而其余的应该是4个字节。 / p>

如果我在函数中设置断点,则值为state为2.假设状态的内存地址确定为0x00000008。

inputData的内存地址返回0x0000000C,inputIndex返回0x00000010,inputLength返回0x00000014。

第一个问题,为什么inputData后的4个字节的内存地址和inputData后的inputIndex 4个字节?不应该将state和inputData分别为8个字节吗?

第二个问题,如果我实际检查值应该的位置的内存地址,它们就在那里,但是哪里是1? 1位于0x00000000。

这怎么会发生?我的错误假设是什么?我做错了什么?

1 个答案:

答案 0 :(得分:1)

这是由x64模式下的调用约定引起的。实际上,在x64中没有cdecl,没有stdcall,没有fastcall - 这些指令被忽略。

在Windows中,x64模式中只有一个调用约定 - Microsoft x64调用约定。在此约定中,如果每个参数的大小为1,2,4或8个字节,则前四个参数将在寄存器中传递,而不是通过堆栈传递。同时,保留32个字节用于调试目的。

这意味着获取输入参数的地址并直接从堆栈读取其值是没有意义的。

尝试在控制台上打印值,而不是在调试器中查看其值。还要检查可能强制使用cdecl而不是默认x64调用约定的编译器选项。