首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么C函数不能被命名为乱码?

为什么C函数不能被命名为乱码?
EN

Stack Overflow用户
提问于 2016-04-14 19:34:18
回答 5查看 13K关注 0票数 139

我最近接受了一次采访,其中一个问题是extern "C"在C++代码中的用途是什么。我回答说,它是在C++代码中使用C函数,因为C不使用名称损坏。有人问我为什么C不使用名称损坏,老实说,我无法回答。

据我所知,当C++编译器编译函数时,它会为函数指定一个特殊的名称,这主要是因为我们可以在C++中使用必须在编译时解析的同名重载函数。在C中,函数的名称将保持不变,或者前面可能有一个_。

我的疑问是:允许C++编译器也破坏C函数有什么错?我会假设编译器给它们起什么名字并不重要。我们在C和C++中以相同的方式调用函数。

EN

回答 5

Stack Overflow用户

发布于 2016-04-14 22:53:17

程序部分用C语言编写,部分用其他语言编写(通常是汇编语言,但有时是Pascal、FORTRAN或其他语言),这是很常见的。程序中包含不同组件的情况也很常见,这些组件是由不同的人编写的,这些人可能并不具备所有内容的源代码。

在大多数平台上,有一种规范--通常称为ABI应用程序二进制接口,它描述了编译器必须执行哪些操作才能生成具有特定名称的函数,该函数接受某些特定类型的参数并返回某个特定类型的值。在某些情况下,ABI可能会定义多个“调用约定”;这类系统的编译器通常会提供一种方法来指示应该为特定函数使用哪种调用约定。例如,在Macintosh上,大多数工具箱例程都使用Pascal调用约定,因此类似于"LineTo“的原型应该是这样的:

代码语言:javascript
复制
/* Note that there are no underscores before the "pascal" keyword because
   the Toolbox was written in the early 1980s, before the Standard and its
   underscore convention were published */
pascal void LineTo(short x, short y);

如果项目中的所有代码都是使用相同的编译器编译的,那么编译器为每个函数导出的名称并不重要,但在许多情况下,C代码将有必要调用使用其他工具编译的函数,这些函数不能用当前的编译器重新编译,甚至可能不是用C编写的。因此,能够定义链接器名称对于使用这些函数至关重要。

票数 13
EN

Stack Overflow用户

发布于 2016-04-15 19:54:23

我将添加另一个答案,以解决发生的一些无关的讨论。

C ABI (应用程序二进制接口)最初调用的是以相反的顺序(即从右到左)传递堆栈上的参数,调用者也会释放堆栈存储。现代ABI实际上使用寄存器来传递参数,但许多损坏的考虑因素都可以追溯到最初的堆栈参数传递。

相比之下,原始的Pascal ABI将参数从左推到右,被调用者必须弹出参数。原始的C ABI在两个重要方面优于原始的Pascal ABI。参数推送顺序意味着第一个参数的堆栈偏移量始终是已知的,允许具有未知数量的参数的函数,其中早期参数控制有多少其他参数(ala printf)。

ABI的第二个优势是在调用者和被调用者不同意有多少参数的情况下的行为。在C语言中,只要不实际访问最后一个参数之后的参数,就不会发生什么不好的事情。在Pascal中,从堆栈中弹出错误数量的参数,整个堆栈就会损坏。

最初的Windows3.1ABI是基于Pascal的。因此,它使用Pascal ABI (参数按从左到右的顺序,被称为pops)。由于参数数量的任何不匹配都可能导致堆栈损坏,因此形成了损坏方案。每个函数名都用一个数字表示其参数的大小,以字节为单位。因此,在16位机器上,以下函数(C语法):

代码语言:javascript
复制
int function(int a)

被损坏为function@2,因为int有两个字节宽。这样做的目的是,如果声明和定义不匹配,链接器将无法找到函数,而不是在运行时损坏堆栈。相反,如果程序链接,则可以确保在调用结束时从堆栈中弹出正确的字节数。

32位Windows32位及以上版本使用stdcall ABI。它类似于Pascal ABI,除了按顺序类似于C语言,从右到左。与Pascal ABI类似,名称损坏将参数字节大小损坏为函数名称,以避免堆栈损坏。

与这里其他地方的声明不同,C ABI不会破坏函数名称,即使在Visual Studio上也是如此。相反,使用stdcall ABI规范修饰的函数并不是VS独有的。即使在为Linux编译时,GCC也支持这种ABI。这被Wine广泛使用,它使用自己的加载器来允许运行时将Linux编译的二进制文件链接到Windows编译的DLL。

票数 12
EN

Stack Overflow用户

发布于 2016-04-14 19:40:57

C++编译器使用名称损坏,以便允许重载函数具有唯一的符号名称,否则这些函数的签名将是相同的。它基本上也对参数的类型进行了编码,这允许在基于函数的级别上进行多态性。

C不需要这样做,因为它不允许重载函数。

请注意,名称损坏是其中之一(但肯定不是唯一的!)一个人不能依赖“C++ABI”的原因。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36621845

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档