【发布时间】:2013-06-22 13:41:41
【问题描述】:
我遇到了一些意外行为,这可能意味着我不完全理解编译器在做什么。考虑以下人为设计的程序:
#include <stdio.h>
#pragma pack(push, 1)
struct A {
unsigned short a;
unsigned short b;
explicit A() {
printf("construct\n");
}
~A() {
printf("destruct\n");
}
};
#pragma pack(pop)
static_assert(sizeof(A) == 4, "sizeof(A) != 4");
A __stdcall f(int p1, A p2, int p3, int p4) {
printf("%08X %08X %08X %08X\n", p1, p2, p3, p4);
return p2;
}
int main() {
__asm {
push 4
push 3
push 2
push 1
call f
}
return 0;
}
上面的程序会崩溃,但是如果我从struct A 中删除A() 和~A() 的定义,它不会。这个问题与编译器认为参数在堆栈上的位置有关,定义的构造函数认为它们比它们所在的位置多 4 个字节。如果我删除构造函数,我得到的输出是这样的:
00000001 00000002 00000003 00000004
这是我所期望的,但是我得到了定义的构造函数
00000002 00000003 00000004 00000000
这显然不是我所期望的。运行前者时,函数返回RETN 0x10,后者返回RETN 0x14,所以看起来它认为应该有另一个参数(为什么?)。我注意到,如果我将 f 更改为 void 函数,它会按预期工作。那么,有人可以向我解释发生了什么以及为什么吗?我关闭了所有优化。
【问题讨论】:
-
p2的类型为A。然而你正在传递一个int。我很惊讶它完全有效,因为这是完全未定义的。你确定这是正确的代码吗? -
@Adrian
A与int大小相同,并且它没有虚函数,所以我不明白为什么它不应该工作 -
当 A 是非 POD 时,您将出现意外行为。如果您真的想这样做,请反汇编编译器所做的事情以查看真正发生的事情。
-
@Adrian 是的,这似乎是问题所在。我只使用这些结构来解析游戏内存中的对象,所以这就是为什么它看起来有点奇怪,我猜。
标签: c++ visual-studio-2010 visual-c++ assembly