重载内置(内在?)功能

时间:2014-11-08 20:11:06

标签: c++ visual-c++ gcc clang built-in

请考虑以下代码:

#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打印42;
  • 为clang打印0

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

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

2 个答案:

答案 0 :(得分:5)

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

C11标准,§7.12.6.7:

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

§7.1.2:

  

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

[extern.names] / 3:

  

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

根据[reserved.names] / 2,行为未定义;因此,实现可以按照自己的意愿行事,包括发布无意义的错误消息。

答案 1 :(得分:2)

所以根据标准(17.6.1.2.4):

  

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

未指明log()中的math.h(真cmath)是否在名称空间std中。如果是(就像libstdc ++ for gcc那样),那么调用log(1)非常简单地调用你的函数,因为另一个名为std::log()。但是对于clang来说,显然它把它放在全局命名空间中。因为有一个

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

因为你传递了一个int,所以你会更喜欢这个,所以在clang上它会调用那个。 (我现在无法检查,因为我无法访问coliru并且没有安装clang,但这是最佳猜测。)