标准库函数abs()在不同C ++编译器上的异常行为

时间:2018-01-04 05:11:32

标签: c++ language-lawyer libstdc++ c++-standard-library libc++

考虑以下计划:

#include <cstdio>
#include <cmath>

int main()
{
    int d = (int)(abs(0.6) + 0.5);
    printf("%d", d);
    return 0;
}

g++ 7.2.0输出0(参见实时演示here

g++ 6.3.0(参见实时演示here

prog.cc: In function 'int main()':
prog.cc:6:26: error: 'abs' was not declared in this scope
     int d = (int)(abs(0.6) + 0.5);
                          ^
prog.cc:6:26: note: suggested alternative:
In file included from prog.cc:2:0:
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/cmath:103:5: note:   'std::abs'
     abs(_Tp __x)
     ^~~

clang++ 5.0.0输出1(参见实时演示here

clang++ 3.6.0(参见实时演示here

prog.cc:6:19: error: use of undeclared identifier 'abs'; did you mean 'fabs'?
    int d = (int)(abs(0.6) + 0.5);
                  ^~~
                  fabs
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:181:14: note: 'fabs' declared here
__MATHCALLX (fabs,, (_Mdouble_ __x), (__const__));
             ^
/usr/include/math.h:71:26: note: expanded from macro '__MATHCALLX'
  __MATHDECLX (_Mdouble_,function,suffix, args, attrib)
                         ^
/usr/include/math.h:73:22: note: expanded from macro '__MATHDECLX'
  __MATHDECL_1(type, function,suffix, args) __attribute__ (attrib); \
                     ^
/usr/include/math.h:76:31: note: expanded from macro '__MATHDECL_1'
  extern type __MATH_PRECNAME(function,suffix) args __THROW
                              ^
/usr/include/math.h:79:42: note: expanded from macro '__MATH_PRECNAME'
#define __MATH_PRECNAME(name,r) __CONCAT(name,r)
                                         ^
/usr/include/x86_64-linux-gnu/sys/cdefs.h:88:23: note: expanded from macro '__CONCAT'
#define __CONCAT(x,y)   x ## y
                        ^
1 error generated.

Microsoft VC ++ 19.00.23506输出1(参见实时演示here

这个计划到底发生了什么?为什么在不同的C ++编译器上编译时会给出不同的输出?为什么程序即使在同一编译器的不同版本上也会表现出不同此编译器问题或标准库(libstdc++&amp; libc++)是否有问题? C ++标准对此有何看法?

P.S:我知道我需要写std::abs而不是abs。但这不是我的问题。

1 个答案:

答案 0 :(得分:7)

从C标准库引入功能的所有cname库头必须在名称空间std中引入这些符号。他们也可能,但绝对不是必须将它们引入全局namesapce。 [headers]/4

  

除条款[library]至[thread]和附件中所述外   [depr],每个头文件名的内容与该文件的内容相同   C标准库中指定的相应头名.h。在   但是,C ++标准库是声明(名称除外)   在C)中被定义为宏的是在命名空间范围内   命名空间标准。这些名称是否未指明(包括任何名称)   通过[thread]和。在子句[language.support]中添加的重载   附件[depr])首先在全局命名空间范围内声明   然后通过显式的using-declarations注入到命名空间std中。

所以不同的编译器,甚至不同的编译器版本,都意味着不同的实现细节。