C++ 如何检测/查找64位结构对齐问题
我们有一个相当旧的代码库,我们正在迁移到64位以使用一些新的第三方64位工具。我们在Windows 7上运行,使用VS2010,以及用C++编写的代码。 我们花了两天时间试图找出一个问题,即成员变量未设置为预期值。使用VS2010内存调试器,我们可以看到成员变量内存位置偏移了四个字节。一些研究将我们引向结构对齐和64位 事实证明,类中定义的第一个变量是32位整数,第二个变量是指针。如果我们将指针移到类的顶部,所有成员变量都会正确对齐。这解决了问题 我们也注意到C++ 如何检测/查找64位结构对齐问题,c++,visual-studio-2010,64-bit,C++,Visual Studio 2010,64 Bit,我们有一个相当旧的代码库,我们正在迁移到64位以使用一些新的第三方64位工具。我们在Windows 7上运行,使用VS2010,以及用C++编写的代码。 我们花了两天时间试图找出一个问题,即成员变量未设置为预期值。使用VS2010内存调试器,我们可以看到成员变量内存位置偏移了四个字节。一些研究将我们引向结构对齐和64位 事实证明,类中定义的第一个变量是32位整数,第二个变量是指针。如果我们将指针移到类的顶部,所有成员变量都会正确对齐。这解决了问题 我们也注意到 在类的顶部添加一个四字节缓冲区“修
class-CTaskBar
{
公众:
布尔CreateTaskbarIcon(HWND-HWND,
HINSTANCE HINSTANCE,
未被注意到的信息,
中国联通,
LPCTSTR(标题)
{
if(hWnd==NULL)
返回false;
if(hInstance==NULL)
返回false;
m_hWnd=hWnd;
m_hInstance=hInstance;
m_nidstaskbaricondata.cbSize=sizeof(notifyiconda);
m_nidstaskbaricondata.hWnd=m_hWnd;
m_nidstaskbaricondata.uID=IDI_TASKBARICON;
国际单项体育联合会(联通){
如果(m_hTaskbarIcon)
销毁图标(m_hTaskbarIcon);
m_hTaskbarIcon=::加载图标(m_hInstance,MAKEINTRESOURCE(unIcon));
m_nidstaskbaricondata.hIcon=m_hTaskbarIcon;
m_nidstaskbaricondata.uFlags |=NIF_图标;
}
如果(未通知消息){
m_nidstaskbaricondata.uCallbackMessage=unNotifyMessage;
m| nidstaksbaricondata.uFlags |=NIF_消息;
}
如果(标题){
strcpy(m_nidstaskbaricondata.szTip,szCaption);
m_nidstaskbaricondata.uFlags |=NIF_TIP;
}
//Shell\u NotifyIcon调用将把图标添加到任务栏中。
if(Shell\u NotifyIcon(NIM\u ADD和m\u nidstaskbaricondata))
返回true;
返回false;
}
私人:
Notifyiconda m_nidstaskbaricondata;
HINSTANCE m_HINSTANCE;
HWND m_HWND;
哈默努姆·赫塔斯卡巴姆努斯;
HICON m_hTaskbarIcon;
};
基本上,应用程序在Windows API调用的最深处崩溃。如果我们查看内存调试器,我们可以看到内存正在设置,但偏移了四个字节。如果我将m_nidstaskbaricondata移到m_hTaskbarIcon之后。在内存调试器中,一切看起来都是正确的,没有崩溃。因此,我们在64位C/C++应用程序上进行了大量搜索。正如Andrey Cpp所指出并链接到的,存在一个基于成员变量顺序和大小的结构对齐问题。不幸的是,PVS Studio没有指出这个问题。我不相信这是一个错误的PVS工作室。进一步的研究和反复试验使我们尝试在VS2013中构建该项目。这个问题在2013年就消失了。我能找到的最接近解释为什么它在VS2013中工作的东西是 在x64上,类的对象布局可能会与以前的版本不同。如果它有一个虚拟函数,但没有一个基类有一个虚拟函数,那么编译器的对象模型会在数据成员布局之后插入一个指向虚拟函数表的指针。这意味着布局可能并非在所有情况下都是最优的。在以前的版本中,X64的优化将尝试改进布局,但由于它无法在复杂代码情况下正确工作,<强>它在Visual C++ 2013中删除了VisualStudio<<强> > /P>
它看起来是VS2010中的一个bug,在VS2013中得到了修复。VS2013中的内存调试器显示了我所期望的对齐方式。当编译64位时,所有带指针的结构都应该至少对齐8个字节。有什么布拉格包装吗?(编辑:哦,我刚刚看到你的第二颗子弹。正在打包。)这对我来说有点像未定义的行为(甚至可能违反一个定义规则),如果是这样的话,静态检查器通常很难检测到。你能提供更多关于这个问题的具体细节吗?@神秘的是,我们知道我们可以设置它,事情似乎可以自行解决。这两个应用程序都进行了一些打包,因为它们通过TCP发送和接收二进制打包消息。当我们意识到设置打包会使事情消失时,我们确实回顾了使用打包来确保在底部重置打包的单个头文件,用#pragma pack(show)重新检查以进行验证。我没有看到好的信号。可能没有完全初始化NotifyIConda,也没有使用NIM_SETVERSION。如果它实际上在shell中崩溃,那么您会得到一个非常好的提示,即它正在访问已释放的内存,或者您现在看到了32位版本中已经存在的潜在堆损坏问题的副作用。