【发布时间】:2023-03-19 09:49:01
【问题描述】:
我发现了这个:
因为堆栈被调用函数清理,__stdcall 调用约定创建比 __cdecl更小的可执行文件,其中 必须为每个函数调用生成堆栈清理代码。
假设我有 2 个函数:
void __cdecl func1(int x)
{
//do some stuff using x
}
void __stdcall func2(int x, int y)
{
//do some stuff using x, y
}
这里是main():
int main()
{
func1(5);
func2(5, 6);
}
IMO,清理对func1(5) 的调用堆栈是main() 的责任,而func2 将清理对func2(5,6) 的调用堆栈,对吧?
四个问题:
1.对于main()中对func1的调用,清理堆栈是main的责任,所以编译器会在调用前后插入一些代码(清理堆栈的代码) func?像这样:
int main()
{
before_call_to_cdecl_func(); //compiler generated code for stack-clean-up of cdecl-func-call
func1(5);
after_call_to_cdecl_func(); //compiler generated code for stack-clean-up of cdecl-func-call
func2(5, 6);
}
2.对于main()中对func2的调用,清理堆栈是func2自己的工作,所以我推测,在调用之前或之后不会在main()中插入代码func2,对吧?
3.因为func2是__stdcall,所以我推测编译器会自动插入代码(清理堆栈)如下:
void __stdcall func1(int x, int y)
{
before_call_to_stdcall_func(); //compiler generated code for stack-clean-up of stdcall-func-call
//do some stuff using x, y
after_call_to_cdecl_func(); //compiler generated code for stack-clean-up of stdcall-func-call
}
我猜对了?
4.最后,回到引用的话,为什么__stdcall 的可执行文件比__cdecl 小?而且linux中没有__stdcall这样的东西,对吧?是不是意味着linux elf在win下总是比exe大?
【问题讨论】:
-
stdcall 不能用于可变参数函数,这就是您在 Linux 上看不到它的原因。它仅在 Windows 上用于 win32 API 调用。本机 Windows 编译器通常使用某种形式的 fastcall 或 cdecl。
-
那么,linux只支持
cdecl? -
@David:实际上他们倾向于使用
__stdcall或__cdecl,因为整个WINAPI 是__stdcall或__cdecl,我从来没有遇到过默认为@987654349 的编译器@nor 和广泛使用它的 API -
@Necrolis 我的日常编译器 Delphi 默认使用 fastcall。 MSVC 默认对 C++ 成员函数使用 fastcall。
-
@Alcott 甚至没有那么简单。考虑 x64。在 Windows 和 Linux(不了解 Mac)上,只有一种 x64 调用约定。
标签: c++ c compiler-construction calling-convention