显然(至少根据gcc -std=c99)C99不支持函数重载.在C中不支持某些新功能的原因通常是向后兼容,但在这种情况下,我无法想到一个函数重载会破坏向后兼容性的情况.不包括这个基本功能的原因是什么?
Sin*_*ion 27
要理解为什么你不太可能在C中看到重载,可能有助于更好地了解C++如何处理重载.
编译代码之后,但在准备运行之前,必须链接中间对象代码.这将编译函数和其他对象的粗略数据库转换为准备加载/运行二进制文件.这一额外步骤很重要,因为它是编译程序可用的模块化的主要机制.此步骤允许您从现有库中获取代码并将其与您自己的应用程序逻辑混合.
在此阶段,目标代码可能已使用任何语言编写,并具有任何功能组合.为了实现这一点,有必要采用某种约定,以便链接器能够在另一个对象引用它时选择正确的对象.如果您使用汇编语言进行编码,那么在定义标签时,会严格使用该标签,因为假设您知道自己在做什么.
在C中,函数成为链接器的符号名称,因此在您编写时
int main(int argc, char **argv) { return 1; }
Run Code Online (Sandbox Code Playgroud)
编译器提供目标代码的存档,其中包含一个名为的对象main.
这很好用,但这意味着你不能拥有两个具有相同名称的对象,因为链接器将无法决定它应该使用哪个名称.链接器对参数类型一无所知,而且通常对代码知之甚少.
C++通过直接将符号名称中的附加信息编码来解决此问题.返回类型以及参数的数量和类型将添加到符号名称中,并在函数调用时以这种方式引用.链接器不必知道这甚至发生了,因为据它所知,函数调用是明确的.
这样做的缺点是符号名称看起来与原始函数名称不同.特别是,几乎不可能预测重载函数的名称是什么,以便您可以链接到它.要链接到foriegn代码,您可以使用extern "C",这会导致这些函数遵循C样式的符号名称,但当然您不能重载这样的函数.
这些差异与每种语言的设计目标有关.C面向可移植性和互操作性.C不遗余力地做出可预测和兼容的事情.C++更倾向于构建丰富而强大的系统,而不是非常注重与其他语言的交互.
我认为C不可能追求任何会产生与C++一样难以交互的代码的功能.
编辑: Imagist问:
如果你将main(int argc,char**argv)解析为main-int-int-char**而不是main(这是main的一部分),它是否真的不那么可移植或者更难以与函数交互?标准)?我这里没有看到问题.事实上,在我看来,这为您提供了更多信息(可用于优化等)
为了回答这个问题,我将再次讨论C++及其处理重载的方式.C++几乎完全按照描述使用这种机制,但有一点需要注意.C++没有标准化应该如何实现自身的某些部分,然后继续建议如何省略这些遗漏的一些后果.特别是,C++有一个丰富的类型系统,包括虚拟类成员.应如何实现此功能由编译器编写者完成,vtable解析的详细信息对函数签名有很大影响.出于这个原因,C++故意建议编译器编写者使编译名称在编译器或具有这些关键特性的不同实现的相同编译器之间互不兼容.
这只是一个更深层次问题的症状,虽然像C++和C这样的高级语言具有详细的类型系统,但是较低级别的机器代码完全没有类型.任意丰富的类型系统建立在机器级别提供的无类型二进制文件之上.链接器无法访问更高级语言可用的丰富类型信息.链接器完全依赖于编译器来处理所有类型的抽象并生成正确的无类型对象代码.
C++通过编码受损对象名称中的所有必要类型信息来实现此目的.然而,C具有明显不同的焦点,旨在成为一种可移植的汇编语言.因此,C优选在声明的名称和结果对象的符号名称之间具有严格的一对一对应关系.如果C Mangled它的名字,即使是以标准化和可预测的方式,你将不得不付出巨大努力将更改的名称与所需的符号名称相匹配,否则你将不得不像在c ++中那样关闭它.这种额外的努力几乎没有任何好处,因为与C++不同,C的类型系统相当小而且简单.
同时,定义几个类似命名的C函数实际上是一种标准做法,这些函数仅根据它们作为参数的类型而变化.有关这方面的冗长示例,请查看OpenGL命名空间.
Meh*_*ari 19
编译C源时,符号名称将保持不变.如果引入函数重载,则应提供名称修改技术以防止名称冲突.因此,像C++一样,您将在编译的二进制文件中生成机器生成的符号名称.
此外,C没有严格的打字功能.许多事情在C中可以隐含地相互转换.重载决策规则的复杂性可能会在这种语言中引入混淆.
很多语言设计师,包括我在内,都认为函数重载与C隐式促销的结合会导致代码难以理解.有关证据,请查看有关C++积累的知识体系.
一般而言,C99旨在成为与现有做法基本兼容的适度修订.超载将是一个相当大的偏差.