我收到了一些意外的行为,这可能意味着我不完全理解编译器在做什么。请看下面的做作程序:从程序集调用C++函数,使用struct参数
#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
@Adrian'A'与int的大小相同,并且没有虚函数,所以我不明白为什么它不起作用 – user1520427
当A是非POD时,将会出现意想不到的行为。如果你真的想这样做,请反汇编编译器做什么来查看真正发生的事情。 – Adrian