重载内置(固有?)功能

Overload built-in (intrinsic?) function

本文关键字:功能 固有 内置 重载      更新时间:2023-10-16

考虑以下代码:

#include <iostream>
#include <math.h>
double log(double) { return 42; }
int main() {
    std::cout << log(1) << std::endl;
}

在构建调试版本时,所有使用的编译器(msvc、gcc、clang)都会打印42

但当我尝试在发布模式下构建(并运行)时,我得到了:

  • msvc:error C2169: 'log' : intrinsic function, cannot be defined中的编译错误
  • 为gcc打印CCD_ 3
  • 为clang打印0

为什么同一编译器的发布/调试结果不同?

为什么不同的编译器在发布模式下会得到不同的结果?

您正在定义一个已在<math.h>中通过外部链接声明的函数。

C11标准,§7.12.6.7:

#include <math.h>
double log(double x);

§7.1.2:

库函数的任何声明都应具有外部链接。

[外部名称]/3:

用外部链接声明的标准C库中的每个名称保留给实现,用作外部为"C"的名称链接,位于命名空间std和全局命名空间中。

根据[reserved.names]/2,行为是未定义的;因此,实现可以随心所欲,包括发布无意义的错误消息。

因此,根据标准(17.6.1.2.4):

然而,在C++标准库中,声明(在C中定义为宏的名称除外)在命名空间std的命名空间范围(3.3.6)内。未指定这些名称是否首先在全局命名空间范围内声明,然后通过显式使用声明(7.3.3)注入命名空间std

未指定math.h中的log()(实际上是cmath)是否在命名空间std中。如果是(就像对gcc的libstdc++一样),那么调用log(1)非常简单地调用您的函数,因为另一个函数名为std::log()。但对于clang,显然它将其放在了全局命名空间中。既然有

template <typename T> double log(T x);

这将比你的更可取,因为你正在传递一个int,所以当clang时,它会调用这个。(我现在无法检查,因为我无法访问coliru,也没有安装clang,但这是最好的猜测)。