The C++ standard defines some overloaded functions in the <cmath>
header that are not part of the <math.h>
header in C (because C doesn't have overloading).
Among these are float abs(float)
, double abs(double)
, long double abs(long double)
, and double abs(Integral)
.
On the other hand, abs
is not defined in the C <math.h>
at all (it is in <stdlib.h>
instead) and the only signature is int abs(int)
.
Now on my systems, when using a C++ compiler with a C++ program, #include <math.h>
does not provide the C++ abs
overloads, either in the global namespace or in std
.
On the other hand, #include <cmath>
defines std::abs
.
This is what I'd expect—include the C version to get the C functions, and include the C++ version to get the C++ functions. This answer by @visitor mentions the same thing.
However, user @Cheers-and-hth-Alf insists that this is a violation of the standard, because it says "Every C header, each of which has a name of the form name.h
, behaves as if each name placed in the standard library namespace by the corresponding cname header is placed within the global namespace scope." (This section, D.5.2, doesn't seem to have changed significantly between C++03, C++11, and C++14.)
It's easy enough to check what your platform does: see what happens with
#include <math.h>
int main() {
abs(1.2);
return 0;
}
If abs
is not declared, then <math.h>
does not include C++ functions.
If it compiles, then try including <stdio.h>
and add printf("%g\n", abs(1.2));
If this complains about a mismatched format, or prints 1, then <math.h>
includes the C int abs(int)
function (normally in <stdlib.h>
).
(It's best to avoid <iostream>
and other C++ headers since they tend to pull in <cstdlib>
and confuse the issue.)
Here's what I've found:
GNU libstdc++
$ g++ -Wall -Wextra abs2.cc -o abs2
abs2.cc: In function 'int main()':
abs2.cc:5:22: error: 'abs' was not declared in this scope
std::cout << abs(1.2) << '\n';
The libstdc++ docs on the subject
recommend including C++-style headers <c*>
rather than C-style headers <*.h>
precisely because
C++-style headers use function overloading, and the C-style headers do not.
Apple libc++
$ clang++ -Wall -Wextra abs2.cc -o abs2
abs2.cc:4:5: error: use of undeclared identifier 'abs'; did you mean 'fabs'?
Additionally, if you also include <stdlib.h>
to get a definition of abs
, clang++ gives
the more helpful error message
abs2.cc:5:5: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
abs(1.2);
^
abs2.cc:5:5: note: use function 'std::abs' instead
abs(1.2);
^~~
std::abs
abs2.cc:5:5: note: include the header <cmath> or explicitly provide a declaration for 'std::abs'
abs2.cc:5:9: warning: implicit conversion from 'double' to 'int' changes value from 1.2 to 1 [-Wliteral-conversion]
abs(1.2);
~~~ ^~~
abs2.cc:5:5: warning: ignoring return value of function declared with const attribute [-Wunused-value]
abs(1.2);
^~~ ~~~
This explicitly says that the float overloads are only available from <cmath>
, not from the
C traditional headers.
Apache libstdcxx
I didn't install it, but examining the math.h header, it brings those functions from <cmath>
which are also defined in C's <math.h>
into the global namespace, but does not include abs
.
OpenWatcom C++
Again, examining the cmath/math.h header,
when used as math.h
it brings the same functions into the global namespace as Apache libstdcxx did, not including abs
.
STLPort
Examining the math.h header, it includes the system's C <math.h>
header, which is not part of the C++ library and so doesn't include abs
. (This is also what g++ and clang++ did.)
Microsoft Visual Studio (Dinkumware)
I don't have access to this myself, but this site claims to compile using Visual C++, and it says
error C4578: 'abs': conversion from 'double' to 'int', possible loss of data
(Did you mean to call 'fabs' or to #include <cmath>?)
So, is literally every major C++ standard library implementation in violation of the standard on this point?
Or are we missing something that the standard says about <math.h>
and other traditional C headers?