为什么C语言中不能进行函数重载?

9
我知道在C语言中不可能进行函数重载,但我想知道:为什么在C++中类内和类外的函数重载被视为相同的情况?
考虑下面这个在C++中声明函数在类外的例子:
foo()
foo(char c)
foo(int a, int b)

如果C++将每个函数头视为唯一的,为什么C不能也这样做呢?
我认为可能是以下原因:
- 函数重载是在C++中引入的,因此在C中不可用。 - 多态是面向对象编程的概念,但C不是面向对象的。
C中没有函数重载的原因是什么?

这里有三个非常不同的问题。哪一个对你来说最重要? - anatolyg
6
当你问自己为什么一种语言(不仅仅是C语言)不支持新语言中的某个功能时,通常的答案如下:(1)将该语言与旧版本进行比较,而不是与新版本进行比较。(2)列出这种语言相对于旧版本引入的功能清单。(3)欣赏这种语言具有这些新功能所代表的进步意义。(4)认识到设计师也是这样想的,并且他们在某个时刻决定要划定一个界限并结束更新。 - Theodoros Chatzigiannakis
这就是为什么C++被发明的原因。 - iammilind
1
请注意,早期的C语言允许调用未声明的函数。在简单的链接模型中,这甚至可能意味着无法进行重载。对于重载函数,您必须在链接时执行重载解析。 - dyp
3个回答

9
也许最重要的原因是缺乏先前的艺术。由标准委员会添加到C中的功能非常少,既没有成为流行扩展,也不是编写严格符合规范的代码所必需的。
C语言有一些模糊定义的“精神”,C99的解释(V5.10)中说道(第3页,强调我的部分):
一些精神方面可以用以下词汇概括: - 相信程序员。 - 不要阻止程序员做需要做的事情。 - 保持语言简单。 - 对于某种操作提供唯一的方法。 - 让它快速运行,即使它不能保证可移植性。
此外,C语言试图与旧版本保持向后兼容性。例如,旧式声明已在C89中被标记为过时,但仍然是C11的一部分。同上引文,第2页:
现有的代码很重要,但现有的实现并不重要。有大量商业价值的C代码存在。我们已经尽力确保这些代码能够被符合标准的实现接受。C89委员会并不想强迫大多数程序员修改他们的C程序,只是为了让它们被一个符合规范的翻译器接受。
C和C++之间的一些区别至少部分原因是函数重载,例如字符常量的类型。
int foo(int);
int foo(char);
...
    foo('x');

在C++中,这将调用foo(char),但在C中,'x'的类型是int,因此结果可能会令人惊讶,或者'x'需要是char类型,这可能会破坏现有的代码。此外,您可能希望在有意义的地方进行一些提升,例如如果在上一个示例中没有给出foo的第二个声明,则'x'将被提升为int并调用foo(int)。这样的规则可以变得非常复杂(void *是否应该隐式转换为函数调用?)。(不是硬性数字,但C++标准中有关函数重载的章节(第13章)在n3797草案中占据了约30页,ibid章节5.2.2关于函数调用的部分比相应的C标准部分要长得多。)
几乎C的每个特性都是构成最小语言所必需的(好吧,除去历史遗留问题),很少有语法糖;函数重载可以被认为是这样的(您可以将函数命名为foo_intfoo_char等,并明确调用正确的函数)。
您提出的原因是循环的(因此不适用):C确实采用了一些C++功能(例如函数原型);并且在C++中引入了函数重载,因为C缺少它(您不能说“它不是C的一部分,因为它是C++的一部分;而它是C++的一部分,因为它不是C的一部分”)。第二个关于C和OOP的建议也是如此。
我个人喜欢C的原因是它与机器非常接近。通常很容易看出从C代码生成的汇编输出与其相关。符号名称未被混淆,可以轻松识别。语言保持简单和最小化。坦白地说,我不明白人们希望看到某些C++功能合并到C中时追求什么:我们有C ++,这种语言提供了这些功能,具有编写特定于平台的高效代码的能力;为什么不直接使用它呢?
C11引入了_Generic,这可能会对您有所帮助。

8
你可能会在C99 rationale 7.22/25 类型通用数学<tgmath.h>中发现一些有趣的点:

对于一些函数,例如copysign,重载整数和浮点类型也很有用。使用不同数量的参数进行重载将允许重复使用名称,例如将remainder用于remquo。然而,这些设施将使规范变得复杂;并且它们的自然一致使用,例如用于浮点abs或两个参数的atan,将为了不充分的利益引入进一步的与C89的不一致。

C11标准还引入了类型_Generic宏,允许将不同类型处理为类似函数的宏参数。


3

我认为C语言没有函数重载的首要原因是C语言不会对函数名进行编码:

C语言中的每个函数都被转换成具有相同名称的符号,而在C++中则会对函数名进行编码。

举个例子:

以您的函数为例:

void foo()
void foo(char c)
void foo(int a, int b)

C++代码生成的符号名称将如下所示:

void foo() = _Z3foov
void foo(char c) = _Z3fooc
void foo(int a,int b) = _Z3fooii

在 C 代码中,这将被翻译为:

void foo() = foo

底线 - C++ 允许名称重整,因此编译器“更改”函数名称和所有引用的三个不同名称。

C 不允许名称重整到最新标准(我怀疑这将永远不会改变),因此这样的解决方案是不可能的。


4
C和C++标准都没有关于符号或名称重整的规定。 - T.C.
7
我认为情况恰恰相反——C语言不使用名称重整是因为它不需要支持函数重载。 - anatolyg
1
@T.C.:这个问题不是关于标准的内容(那么答案很容易:C没有重载,因为标准规定了这一点,而C++由于同样的原因具有重载),而是关于它们被编写的方式的原因。因此,它涉及到语言实现和哲学;C++实现通常会对名称进行混淆,而C实现则不会。但我同意Anatolyg的观点,如果没有解释为什么可能不希望使用名称混淆,那么这个答案的推理就是循环的。 - mafso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接