为何调用约定不同的函数可互相调用,且MSVC不报编译错误?
为什么MSVC没有抛出编译错误
你提供的示例代码本身不存在不同调用约定函数互相调用的情况:__stdcall修饰的funcA内部是递归调用自身,调用方和被调用方的调用约定完全一致,自然不会触发任何报错。
如果你是笔误想测试funcA调用__cdecl修饰的funcB的场景,这种情况编译器也不会报错,核心原因如下:
- 调用约定属于编译器的平台扩展规则,不属于C标准强制要求诊断的错误范畴
C标准本身没有定义任何调用约定,__cdecl、__stdcall都是MSVC针对Windows平台的自定义扩展,标准只要求同一个函数的所有声明必须完全一致,编译器没有强制义务在不同调用约定的函数互相调用时抛出错误。 - 只要函数声明正确,不同调用约定的函数本来就可以正常互相调用
你担心的栈失衡问题的触发前提是调用方看到的函数声明的调用约定,和函数实际实现的调用约定不匹配,而不是「调用方自身的调用约定和被调用方的调用约定不同」。
比如你在__stdcall的funcA里调用__cdecl的funcB时,编译器能看到funcB的完整声明,知道它是__cdecl约定,会自动生成符合__cdecl要求的调用逻辑:由调用方funcA在调用完成后清理栈,完全匹配funcB的要求,根本不会出现栈失衡的问题。
只有当函数的声明和实现调用约定不匹配时,才会出现问题。比如你在头文件里声明funcB是__stdcall,实际实现的时候写成了__cdecl,这种时候编译器编译调用方时会按照__stdcall生成调用逻辑,但实际实现是__cdecl,就会触发栈失衡。这种场景下MSVC通常会在链接阶段抛出符号不匹配的错误,因为不同调用约定的函数名字修饰规则不同:__cdecl的C函数名字前加下划线,__stdcall的C函数名字格式为_函数名@参数总字节数,链接时会找不到对应符号。
内容的提问来源于stack exchange,提问作者Suric
相关产品推荐
相关产品推荐

