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

问题描述 投票:0回答:1

考虑以下程序:

#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(观看现场演示这里

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(观看现场演示这里

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(参见现场演示这里

这个程序到底发生了什么?为什么在不同的 C++ 编译器上编译时会给出不同的输出?为什么即使在同一编译器的不同版本上,程序也会表现出不同的行为?这是编译器问题还是标准库 (

libstdc++
&
libc++
) 问题? C++ 标准对此有何规定?

P.S:我知道我需要写

std::abs
而不是
abs
。但这不是我的问题。

c++ language-lawyer libstdc++ c++-standard-library libc++
1个回答
8
投票

所有从 C 标准库引入功能的

cname
库头文件必须在命名空间
std
中引入这些符号。他们也可能,但绝对不是必须将它们引入全局命名空间。 [标题]/4:

除了 [库] 到 [线程] 和附件中的条款 [depr],每个header cname的内容与 C 标准库中指定的相应头文件 name.h。在 C++ 标准库,然而,声明(名称除外 在 C 中被定义为宏)在 命名空间标准。不确定这些名称(包括任何 通过 [thread] 和 [language.support] 条款中添加的重载 附件 [depr]) 首先在全局命名空间范围内声明,并且 然后通过显式使用声明注入到命名空间 std 中。

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

© www.soinside.com 2019 - 2024. All rights reserved.