c++ - 编译器在构造函数中计算的成员偏移量不正确
问题描述
VC++ 编译器由于未知原因在构造函数中为具有以下结构的类生成不正确的成员偏移量:
class AlignTest
{
public:
enum TEnum : char
{
one,
two
};
protected:
int& ref;
char c;
size_t keyVar;
public:
AlignTest(int& x. size_t other = 0) : ref(x)
{
c = 1;
keyVar = other;
}
void Print();
};
由于在构造函数执行期间的未知原因,keyVar 赋值写入地址 this+0x09,但由于对齐,keyVar 实际上在 this+0x10。令人惊讶的是,在运行 Print 方法时,代码会正确生成并将 keyVar 解析为 this+0x10。
几点观察:
- 将 alignof(8) 添加到 keyVar 可以解决问题
- 将构造函数的定义移动到 cpp 文件可以解决问题
- 在标题中使用初始化列表时出现同样的问题
- 无法在较新的编译器上的不同项目中重现简化版本(正在处理它)
- 如果在定义构造函数时类中使用的每种类型都是众所周知的,则检查标头。
- 运行调试,关闭优化,x64,工具集:windowsapplicationfordrivers10.0,VS2017。
似乎构造函数代码没有考虑 keyVar 对齐。是否有一些标准/编译器限制或者它只是编译器错误/副作用?
用 VS 用一段反汇编代码更新,注意从“这个”地址的偏移量。
在 .h 文件的构造函数中:
keyVar = other;
00007FF76C32D4DB 48 8B 44 24 08 mov rax,qword ptr [this]
00007FF76C32D4E0 48 8B 4C 24 18 mov rcx,qword ptr [other]
00007FF76C32D4E5 48 89 48 09 mov qword ptr [rax+9],rcx
在 Print 方法中:
size_t tmp2 = keyVar;
00007FF76C3918D0 48 8B 84 24 40 02 00 00 mov rax,qword ptr [this]
00007FF76C3918D8 48 8B 40 10 mov rax,qword ptr [rax+10h]
00007FF76C3918DC 48 89 44 24 68 mov qword ptr [rsp+68h],rax
更新
似乎原始项目有问题。我已将可疑类移至单独的项目,使用相同的编译工具并且无法重现。
周一将开始另一种方式——从原始项目中删除一些东西,看看会有什么不同。
解决方案
正如 Igor Tandetnik 建议的那样,问题出在具有构造函数 (1) 的编译单元和具有打印方法 (8) 的单元中的不同包级别。在项目标头之一中发现未还原的 pack(1) 指令。
推荐阅读
- javascript - Vue类与字符串绑定?
- php - adobe muse 表单不发送电子邮件
- jpa - 我们如何从 spring data jpa 中获取选定的列列表?
- ios - 目标 C 函数未在 swift 类中调用
- c# - 如何获取 app.config 中所有连接字符串的列表
- python-3.x - 我如何在 tkinter 中单独控制每个按钮
- javascript - 使用jquery动画角度5动画方式(平滑滚动)
- spring - 当我使用 @Requestbody 时,我从带有 @Data 的实体中得到了 null
- java - 类型转换和泛型类型
- c++ - 了解复制构造函数和引用