Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the C++ standard require `#include <math.h>` to define the `abs` overloads found in `<cmath>`?

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?

like image 854
Nick Matteo Avatar asked May 04 '16 21:05

Nick Matteo


People also ask

What are the C standards?

What is the C programming language standard? It is the standard way defined for the compiler creators about the compilation of the code. The latest C standard was released in June 2018 which is ISO/IEC 9899:2018 also known as the C11.

Does C require Main?

c does not require a main() function. Show activity on this post. main is mandatory to be present if you are building your code into an application as main functions serves as an entry point for the application. But, if your code is being built as lib, then main is not needed.

Do you need to declare variables in C?

Variable declarations. Before you can use a variable in C, you must declare it.

Which of the following are required when declaring a variable in C?

Rules for defining variablesA variable name can start with the alphabet, and underscore only. It can't start with a digit. No whitespace is allowed within the variable name. A variable name must not be any reserved word or keyword, e.g. int, goto, etc.


1 Answers

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

like image 138
Galik Avatar answered Sep 21 '22 05:09

Galik