C和C++调用约定有什么区别?

Kad*_*iam 7 c c++ compiler-construction linker calling-convention

据我所知,调用约定依赖于编译器和体系结构.但C和C++调用约定之间是否存在明显差异?

Kon*_*lph 10

但C和C++调用约定之间是否存在明显差异?

一般来说,没有.C++被有意设计为尽可能与C兼容,特别是它在所有系统上使用C应用程序二进制接口.

但是C ABI不能满足C++需要的许多功能(特别是重载,命名空间和函数模板),因此C++编译器对函数名称进行了一些更改.这称为名称修改

因此,为了使C和C++代码之间的函数调用起作用,必须声明这样的函数extern "C"禁用名称修改并确保调用约定是C所期望的那些(但我希望后一个方面自动出现,即使标准不强制要求).

C++还为C中不存在的成员函数(有时称为thiscall)提供了额外的调用约定.但是,自由函数使用与C相同的调用约定,无论哪个在给定系统上.

  • 我没有看到任何保证在这里说的话.C++中唯一与C相同的调用约定是声明为extern"C"的函数.但我以前知道错了.如果你有参考,那就太好了. (4认同)
  • @LokiAstari Bjarne Stroustrup有几本书都是这么说的. (2认同)
  • 你需要稍微讨论名称修改.C ABI没有或最小的名称重整.C++会破坏未声明为"extern"C"`的所有内容.Mangling对参数和返回类型进行编码,并在C++中对所有函数(成员或非成员)完成. (2认同)

Ste*_*sop 6

在任何标准中都没有要求C和C++调用约定在给定编译器上是相同的,除了声明extern "C"必须使用与C函数相同的调用约定调用的C++函数.

这就是为什么指向函数的指针和带有相同参数和返回类型的带C指令的指针具有不同的类型.当调用该函数时,编译器可以从类型中知道调用它的调用约定,如果它们不同.

在实践中,我不认为我曾经故意处理过使用具有和不具有C链接的自由函数之间的不兼容调用约定的示例.通常,C++实现从其计划运行的系统的ABI采用其调用约定,以便生成系统的其他用户可以根据ABI理解的可链接对象(可执行文件和库).

这不是必需的 - 标准不关心是否存在系统ABI,并且系统通常不关心如何在自包含的可执行文件[*]内进行调用.除非有一些特殊的理由不这样做,否则这样做是明智的.给定系统上的系统ABI可能会也可能不会提到C++ - 如果没有,那么就非C语言链接函数而言,C++实现是独立的,但正如我所说,制作可能的函数通常是明智的.C链接使用相同的调用约定,就好像它们有C链接一样.

我说"不兼容"而不是"不同",因为当然有一些事情在C调用约定中没有提到但需要在C++调用约定中指定.例如,如何传递指向成员函数的指针.很可能这不是系统ABI所固定的,因此留待C++实现.这样做的原因是将指向成员函数的指针实现到C++实现,而不是系统ABI执行制造商认为是C++编译器编写器的工作.

使用调用约定时,请注意,在具有或不具有C链接的自由函数之间,名称修改不可避免地存在差异.原因是C++名称修改必须包含参数的类型(因为函数重载),而C名称修改必须不能(因为extern函数声明带有未指定的参数).

[*]虽然我已经看过使用"错误"调用约定会破坏事物的例子.ISTR是Windows移动设备,如果您将堆栈格式化为与操作系统预期的不同,那么某些硬件异常会占用设备,因为操作系统试图回溯违规线程的堆栈,而不能.所以至少在操作系统版本上,可能在2005年左右,如果你想要操作系统的诊断工作,那么你必须在内部使用Windows调用约定.或者无论如何,调用约定的部分与堆栈帧格式有关.当然,这完全是我们的搞砸了,但我不知道我们是否可以通过为硬件异常安装我们自己的处理程序来正确修复它,而不是通过首先不引起异常来解决它们.这确实意味着用户模式进程可以通过堆栈溢出来简单地降低操作系统,并且调试代码比在其他Window上更难.所以我们稍微指责操作系统.