【问题标题】:standard library not raising error for duplicate definition [duplicate]标准库不会为重复定义引发错误 [重复]
【发布时间】:2023-03-20 22:59:01
【问题描述】:

既然c++标准库做了外部链接,为什么不返回重复函数定义的错误。

这不应该是函数重载,因为它是 double(double,double) 类型,与 math.h 中定义的 pow 完全相同

#include <iostream>
#include <math.h>

double pow(double base, double exponent) {
    return 1;
}

int main() {
    std::cout << pow(2, 2);
}

【问题讨论】:

标签: c++ c++-standard-library linkage


【解决方案1】:

函数签名pow(double, double) 保留给全局命名空间中的语言实现。通过定义保留名称,程序的行为是未定义的。

那么程序的行为是未定义的,你不能保证“重复定义引发错误”。

相关标准规则(来自最新草案):

[reserved.names.general]

如果程序在保留名称的上下文中声明或定义名称,除非 [library] 明确允许,否则其行为未定义

[extern.names]

使用外部链接声明的 C 标准库中的每个名称都保留给实现,用于在命名空间 std 和全局命名空间中用作具有外部“C”链接的名称。

使用外部链接声明的 C 标准库中的每个函数签名都保留给实现,以用作具有 extern "C" 和 extern "C++" 链接的函数签名,或作为全局命名空间中命名空间范围的名称.

【讨论】:

  • 你确定这个推理吗? stackoverflow.com/a/33856407/580083
  • @DanielLangr 我添加了一些限定条件。
  • 即使现在我也不相信这个推理是正确的。 stackoverflow.com/q/50925440/580083
  • 感谢您的澄清。链接答案中的引用仅表示 每个函数签名 是保留的。
  • @DanielLangr 我改为“函数签名”而不是“名称”。
【解决方案2】:

为什么这不会返回重复函数定义的错误...?

因为C库提供的pow的定义不需要在包含的头文件中。这个头文件 (math.h) 可能只包含它的声明。在这种情况下,生成的翻译单元可能如下所示:

...
double pow(double, double);
...

double pow(double base, double exponent)
{
    return 1;
}

int main()
{
    std::cout << pow(2, 2);
}

这个翻译单元绝对没有问题。但是,问题出现在链接期间,因为链接器可以将您的pow 调用链接到机器代码级别的两个不同函数——一个由 C 库提供,另一个由从翻译单元创建的目标文件提供。

C++ 标准没有定义链接器实际执行的操作。它只是说您的代码的行为是未定义的。

【讨论】:

  • 虽然保留名称部分说行为未定义,正如我在回答中所涵盖的那样,如果我们忽略这一点,那么 ODR 规则会说程序格式错误(不需要诊断)。据我所知,UB 和 IFNDR 之间并没有实际区别。
  • @eerorika 我同意。我只是试图解释编译器在实践中如何处理这段代码。
猜你喜欢
  • 2013-10-27
  • 2012-10-19
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多