C 和 C++ 编译器的问题
Posted
技术标签:
【中文标题】C 和 C++ 编译器的问题【英文标题】:Trouble with C and C++ compiler 【发布时间】:2012-12-05 00:08:30 【问题描述】:我在尝试将 32 位产品转换为 64 位产品时遇到问题。我使用的是 Visual Studio 2008,代码是 C 和 C++。我希望任何人都可以查看以下两行代码,一行来自 C 源文件,另一行来自 C++ 源文件。这两个文件都包含在 DLL 中。我还包括了两行代码的反汇编。
ewxlcom.c
memcpy(pCM->pSecAccInfo->spUserID,userSecurityInfo.spUserID,
sizeof(UserID));
000000000EF33BB9 mov r8d,80h
000000000EF33BBF mov rdx,qword ptr [rsp+828h]
000000000EF33BC7 mov rcx,qword ptr [rsp+1F8h]
000000000EF33BCF mov rcx,qword ptr [rcx+0BDEh]
000000000EF33BD6 call memcpy (0EF40352h)
tcputil.cpp
memcpy(serv_temp+INIT_MSG_USERID_OFFSET, pCM->pSecAccInfo->spUserID, INIT_MSG_USERID_LEN);
000000000EF3B8E6 lea rcx,[rsp+67h]
000000000EF3B8EB mov r8d,80h
000000000EF3B8F1 mov rdx,qword ptr [rsp+3B0h]
000000000EF3B8F9 mov rdx,qword ptr [rdx+0CBEh]
000000000EF3B900 call memcpy (0EF40352h)
如您所见,第一行将一些字节复制到pCM->pSecAccInfo->spUserID
指向的内存中。第二行将这些相同的字节复制到内存中的另一个位置。 ASM memcpy
将字节从寄存器rdx
指向的内存复制到寄存器rcx
指向的内存。所以在第一行中,一个值被移入寄存器rcx
。我已经验证指向pCM
。然后将rcx + 0BDEh
指向的值复制到rcx
中。并调用了memcpy
。这行得通。
但稍后在第二行将一个值加载到寄存器rdx
。我已经验证这也指向与第一行相同的pCM
。然后它加载驻留在内存中的指针,该指针与pCM
(rdx
) 偏移0CBEh
。那段内存全为零,所以memcpy
崩溃了。
问题是为什么编译器会为同一个源变量生成不同的代码。我认为这是一个对齐问题。这是C文件和C++文件之间的区别吗? VS 是否对 C 和 C++ 使用相同的编译器?还有什么我应该看的吗?
任何帮助将不胜感激。
【问题讨论】:
您是否尝试过使用较新版本的 VC++?据我们所知,这是编译器中的一个代码生成问题,此后已得到修复。 :-] 这些是调试版本还是优化?也许您可以显示pCM
指向的任何结构?
另外,pCM->pSecAccInfo->spUserID
中有两个重定向似乎很奇怪,但汇编代码似乎只执行一个(在每个示例中)。例如,在您的第一个程序集 sn-p 中,第一次加载到 rcx
大概是将 pCM
从本地堆栈变量加载到寄存器中,然后 rcx
的下一次加载将加载 pSecAccInfo
- 但 rcx
在调用memcpy()
之前,应该在rcx
中有spUserID
。有可能通过优化,第一次加载实际上是pSecAccInfo
(但你说你验证了它是pCM
)。
【参考方案1】:
如果您要链接 C 和 C++ 代码,您可能需要注意结构中的不同填充特性。也许创建一个临时函数来打印结构的每个成员的偏移量,并将相同的代码从 C 源文件(您编写它的位置)复制到 C++ 源文件。函数的两个副本可以保持不变,因为 C++ 的副本会被破坏,但我会在每个副本的顶部添加一个 printf() 来说明它是哪个版本。然后在崩溃之前从某个地方调用每个,以便您可以比较偏移量。如果它们不同,则需要查看编译器标志来解决该问题。或者...也许您需要添加这样的行...
#ifdef __cplusplus
extern "C"
#endif
.
. ...your struct definitions & variables go here...
.
#ifdef __cplusplus
#endif
...围绕您的结构定义,使 C++ 端具有与项目的 C 端相同的填充行为。
【讨论】:
以上是关于C 和 C++ 编译器的问题的主要内容,如果未能解决你的问题,请参考以下文章
为啥 C 程序会在运行时针对 C++ 库编译和链接 C 编译器然后 SIGILL?