从标准库重新定义一个函数是否违反了一个定义规则?

xsk*_*xzr 5 c++ one-definition-rule c++-standard-library language-lawyer c-standard-library

#include <cmath>

double log(double) {return 1.0;}
int main() {
  log(1.0);
}
Run Code Online (Sandbox Code Playgroud)

假设函数log()in<cmath>是在全局命名空间中声明的(这实际上是未指定的,我们只是假设),那么它引用的函数与log()我们定义的函数相同。
那么这段代码是否违反了一个定义规则(参见这里,因为不需要诊断,这段代码可能会在某些编译器中编译,我们无法断言它是否正确)?

注意:经过最近的编辑,这不是以下内容的重复:C++ 中的一个定义规则究竟是什么?

Pot*_*ter 3

典型场景。

\n\n

如果extern "C" double log(double)最初是在全局命名空间中声明的,那么您已重新声明它并提供了定义。实现之前提到的extern "C"会延续到您的匹配重新声明中。您的定义适用于属于实现的函数,这是 ODR 违规。

\n\n

log至于UB的表现形式:显然,将其视为弱链接符号是很常见的。您的实现会libc.so根据 ABI 规则进行覆盖。

\n\n

(如果实现不这样做extern "C",它仍然基本上是一样的。)

\n\n

其他可能的情况。

\n\n

如果在全局命名空间log中声明namespace std然后带入全局命名空间,那么您的声明将与其冲突。(实际上,using声明在技术上就是声明。)诊断出此错误。

\n\n

违反假设的场景。

\n\n
\n

log那么它指的是与我们定义的函数相同的函数

\n
\n\n

实现将<cmath>名称放入全局命名空间的一种方法是在extern "C"内部声明函数namespace std,然后执行 do using namespace std,并确保在包含任何标准标头时始终将这作为第一件事发生。由于using namespace\xe2\x80\x94 不是“粘性”的,因此它仅适用于指定命名空间 \xe2\x80\x94 中的前面的声明,因此标准库的其余部分将不可见。(这不会在全局命名空间中声明名称,但标准只说“放置在全局命名空间范围内。”)

\n\n

在这样的实现中,您的声明将隐藏标准函数并声明一个具有新的损坏名称(而_Z3logd不是简单的log)和新的完全限定名称(::log而不是::std::log)的新函数。这样就不会有 ODR 违规(除非某些内联函数log在一个 TU 中使用一个函数,而在另一个 TU 中使用另一个函数)。

\n