编译器在构造函数中计算的成员偏移量不正确
Incorrect member offset calculated by compiler in constructor
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解析为这个+0x10。
很少观察到:
- 将alignof(8(添加到keyVar解决了问题
- 将构造函数的定义移动到cpp文件解决了这个问题
- 在标头中使用初始化列表时出现相同问题
- 无法在较新的编译器上在不同的项目中复制简化版本(正在处理(
- 如果在定义构造函数时类中使用的每个类型都是已知的,则检查标头
- 运行调试,关闭优化,x64,工具集:windowsapplicationfordrivers10.0,VS2017
构造函数代码似乎没有考虑keyVar对齐。是否存在一些标准/编译器限制,或者只是编译器缺陷/副作用?
通过VS用一段反汇编的代码更新,注意与"this"地址的偏移量。
在.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
打印方式:
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(指令。
相关文章:
- 编译器在构造函数中计算的成员偏移量不正确
- constexpr 偏移量,带有指向成员数据的指针
- 变量(继承自基模板类)的偏移量,由具有相同名称的成员遮蔽
- 如何在编译时获取成员私有时的偏移量?
- 取参考成员(非 POD)的偏移量
- 与没有临时实例的成员指针的偏移量
- 在编译时确定结构成员字节偏移量
- 通过强制转换 nullptr 获取成员变量的偏移量
- POD声明中成员变量的引用偏移量
- 是指向数据成员及其偏移量的指针
- standard_layout类的数据成员是否与对象的地址有固定的偏移量?
- 如何在编译时输出结构体中成员的偏移量(C/ c++)
- 在特定偏移量中定义成员的结构
- 需要获取结构数据成员的偏移量
- 可以编写一个静态断言来验证数据成员的偏移量吗?
- C++中的可视化数据成员偏移量
- 如何通过其偏移量访问私有数据私有成员
- 使用成员变量的偏移量访问结构体的私有成员
- 指向成员(偏移量)的指针数组作为C++中的模板参数
- 获取 glVertexAttribPointer 模板中的成员偏移量