显然(至少根据 gcc -std=c99
),C99不支持函数重载。通常,不支持C中的某些新功能是出于向后兼容性的考虑,但在这种情况下,我无法想到任何一种情况可以证明函数重载会破坏向后兼容性。为什么没有包含这个基本特性?
显然(至少根据 gcc -std=c99
),C99不支持函数重载。通常,不支持C中的某些新功能是出于向后兼容性的考虑,但在这种情况下,我无法想到任何一种情况可以证明函数重载会破坏向后兼容性。为什么没有包含这个基本特性?
int main(int argc, char **argv) { return 1; }
main
的对象。这很有效,但意味着您不能有两个同名的对象,因为链接器无法决定应该使用哪个名称。链接器不知道任何关于参数类型的信息,对代码的了解也非常有限。 C++通过直接将附加信息编码到符号名称中来解决这个问题。返回类型、参数的数量和类型、参数的引用类型、是否为const
等都添加到符号名称中,并在函数调用点引用。由于链接器可以确定函数调用是唯一的,因此它不必知道正在发生什么。这样做的缺点是符号名称看起来与原始函数名称完全不同。特别是,几乎无法预测重载函数的名称,以便您可以链接到它。要链接到外部代码,可以使用extern "C"
,这使得这些函数遵循符号名称的C风格,但当然您不能重载这样的函数。这些差异与每种语言的设计目标有关。C面向可移植性和互操作性。 C努力做出可预测且兼容的事情。 C++更加强调构建丰富而强大的系统,而不是与其他语言交互。我认为C不太可能追求任何会产生与C++一样难以交互的代码的特性。
编辑: Imagist 问道:
如果你将 int main(int argc, char** argv) 解析为 main-int-int-char **,而不是 main(并且这是标准的一部分),那么与函数交互是否会更不可移植或更困难?我在这里看不到问题。实际上,我认为这给了你更多信息(可以用于优化等)
为了回答这个问题,我再次转向 C++ 及其处理重载的方式。C++ 使用几乎完全按照描述的机制,但有一个注意点。C++ 没有标准化某些部分应该如何实现,然后继续建议某些省略的后果。特别地,C++ 有一个丰富的类型系统,包括虚类成员。如何实现此功能留给编译器编写者,vtable 解析的详细信息对函数签名有很大影响。因此,C++ 故意建议编译器编写者使名称混淆在编译器之间或具有这些关键特性的不同实现的相同编译器之间不兼容。
这只是深层问题的症状,即尽管像 C++ 和 C 这样的高级语言具有详细的类型系统,但低级机器代码完全没有类型。任意丰富的类型系统都建立在机器级别提供的无类型二进制之上。链接器无法访问高级语言可用的丰富类型信息。链接器完全依赖编译器处理所有类型抽象并生成适当的无类型对象代码。
C++通过在编码对象名称中编码所有必要的类型信息来实现这一点。然而,C有一个显著不同的重点,旨在成为一种可移植的汇编语言。因此,C更喜欢在声明名称和生成的对象符号名称之间保持严格的一对一对应关系。如果C混淆了它的名称,即使以标准化和可预测的方式进行,您也必须付出巨大的努力来将更改后的名称与所需的符号名称匹配,否则您就必须像在C++中一样关闭它。这种额外的努力几乎没有任何好处,因为与C ++不同,C的类型系统相当简单。同时,定义几个类似命名的C函数,它们仅因其作为参数的类型而异,实际上是一种标准做法。如果想要详细了解这一点,请查看OpenGL namespace的示例。
int main(int argc, char** argv)
解析为main-int-int-char **
而不是main
(并且这是标准的一部分),那么与函数交互是否真的会更困难或不太便携? 我在这里看不到问题。 实际上,我认为这为您提供了更多信息(可用于优化等)。 - Imagistextern "C"
导出符号的C++编译单元来实现的?C++是一种非常功能丰富的语言。它就像C语言,但具有一些额外的类型安全特性! - SingleNegationEliminationfoo(bar) -> foo-bar
和 foo(baz) -> foo-baz
这样的东西并不难实现。 - Imagist