16

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?

Community
  • 1
  • 1
Nick Matteo
  • 4,453
  • 1
  • 24
  • 35
  • 5
    An interesting and related reading from @JonathanWakely: http://developers.redhat.com/blog/2016/02/29/why-cstdlib-is-more-complicated-than-you-might-think/ – myaut May 04 '16 at 21:16
  • @myaut Indeed, very relevant! It sounds like GCC 6 should be the first platform where `#include ` brings in the `abs` overloads. I will check it out. To be honest, I prefer the notion that `` brings C++-style overloads and `` directly includes the system C header, if you want that. – Nick Matteo May 04 '16 at 21:41
  • Yes, it works: http://melpon.org/wandbox/permlink/jxEYMKonFBkJiaeH – Nick Matteo May 04 '16 at 21:45

1 Answers1

2

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

Galik
  • 47,303
  • 4
  • 80
  • 117
  • Also, it says **name**, not "overload". `abs` is a name. Placing `abs` in the global namespace (without declaring the additional overloads) complies with this requirement – M.M May 04 '16 at 22:54