Does the C++ standard require `#include ` to define the `abs` overloads found in ``?

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 subjectrecommend 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?

3

1 Answer

"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."

That wording, to me, does not say that every name in the <cname> header must appear in the name.h header.

It says that every name in the <name.h> header that has a corresponding name in the <cname> header must appear in the global namespace.

It says nothing about names in the <cname> header that do not appear in the <name.h> header.

C++14 Stadard

D.5 C standard library headers [ depr.c.headers ]

For compatibility with the C standard library and the C Unicode TR, the C ++ standard library provides the 26 C headers, as shown in Table

This statement uses the term "the 26 C headers" suggesting that they contain what the C Standard says they should contain, not what the C++ Standard says that <cname> should contain.

Indeed, regarding <cstddef>, for example, it details things not contained in the corresponding C header.

eg

18.2 Types [ support.types ]

2 The contents are the same as the Standard C library header <stddef.h>, with the following changes...

1

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like