Should I include <xxxx.h> or <cxxxx> in C++ programs?

Since this post is a bit old I wanted to share the following:


Looking at code:

Using X.h   // Compatible with C language standard
---------------
#include <X.h>

int main() {
    // Invoke X's corresponding function
    return 0;
}

Using X    // Not compatible with C language standard
--------------
#include <X>

int main() {
    // Invoke X's corresponding function
    return 0;
}

They both compile and execute ok!


Which one is better in C++?

Regarding C++11's and C++17's specification:

C.5.1 (section from C++17 document)
Modifications to headers [diff.mods.to.headers]

  1. For compatibility with the C standard library, the C++ standard library provides the C headers enumerated in D.5, but their use is deprecated in C++.
  1. There are no C++ headers for the C headers <stdatomic.h>, <stdnoreturn.h>, and <threads.h>, nor are the C headers themselves

part of C++.

  1. The C++ headers <ccomplex> (D.4.1) and <ctgmath> (D.4.4), as well as their corresponding C headers <complex.h> and <tgmath.h>, do not

contain any of the content from the C standard library and instead merely include other headers from the C++ standard library.


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

  1. For compatibility with the C standard library, the C++ standard library provides the C headers shown in Table 141.

enter image description here

Both C++11 and C++17 standard specifications documents state the use of <X.h> remains for compatibility with the C standard, although their use is regarded as deprecated.


Regarding C++ 20 standard proposal

They are reviewing "undeprecating" the use of the C library headers in C++20. <X.h> appear highlighted in green. C++11 and C++17 deprecation, as of now, is stated as a "weak recommendation" and a "tweak" for keeping the "C standard library headers (c.headers)" is displayed below:

"The basic C library headers are an essential compatibility feature, and not going anywhere anytime soon." (from C++ 20 review document)


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

Weak recommendation: In addition to the above, also remove the corresponding C headers from the C++ standard, much as we have no corresponding <stdatomic.h>, <stdnoreturn.h>, or <threads.h>, headers. As above, but with the following tweaks: 20.5.5.2.1 C standard library headers [c.headers]

For compatibility with the C standard library, the C++ standard library provides the C headers shown in Table 141. Table 141 — C headers

 <assert.h>  <inttypes.h>   <signal.h>      <stdio.h>   <wchar.h>
 <complex.h> <iso646.h>     <stdalign.h>    <stdlib.h>  <wctype.h>
 <ctype.h>   <limits.h>     <stdarg.h>      <string.h>  
 <errno.h>   <locale.h>     <stdbool.h>     <tgmath.h>
 <fenv.h>    <math.h>       <stddef.h>      <time.h>
 <float.h>   <setjmp.h>     <stdint.h>      <uchar.h>
 

The header <complex.h> behaves as if it simply includes the header <complex>. The header <tgmath.h> behaves as if it simply includes the headers <complex> and <cmath>.


Bjarne Stroustrup recommends maximising inter-operability between the C and C++ languages, by reducing incompatibilities as much as possible. Others argue otherwise, as it complicates things.

So, it seems <X.h> aren't going anywhere. Ultimately, you can use both. Personally, I would make the decision of which one I would use boil down to having your code backwards compatible with C code or not.


Consider the following programs:

Sample 1:

#include<stdio.h>

int main()
{
    printf("Hello World");
    return 0;
}

Sample 2:

#include<cstdio>

int main()
{
    printf("Hello World");
    return 0;
}

Both work as expected. So which usage is more appropriate? The answer is: Neither! Surprised? Read on.

The C++ Standard library provides all standard C headers for compatibility reason, while C++ as a language also provides all the equivalent headers. As a convention,

  • No C++ standard library headers(apart from ones include for C compatibility) have any file extensions, and
  • All C++ equivalent of C headers begin with cxxxxx.

The C++ Standard mentions this under Annex D (normative) Compatibility features:

Standard Citation

§2 mentions the important distinguishing point. This rule applied to the examples above means:

  • Including cstdio imports the symbol names in the std namespace and possibly in the Global namespace.
  • Including stdio.h imports the symbol names in the Global namespace and possibly in the std namespace.

Let us apply this rule to our sample codes and measure the pros and cons:

Sample 1: This brings all the symbols from stdio.h in the global namespace. Advantage is that you can use the symbols without any qualification since they are imported in the global namespace. Downside is that you end up polluting the global namespace with many symbol names that you will probably never use. This might lead to symbol name collision. In C++ always consider the global namespace as a minefield and avoid it as much as possible.

Sample 2: This is a very bad practice because there is no guarantee that the implementation will put the symbols in global namespace, the standard simply does not demand to do so. We are simply relying on the behavior of one particular compiler implementation. We cannot and should not assume that all compilers will do so. So strictly speaking the program is not standard approved and this usage is not portable across all implementations.

So what is the correct usage?

The correct usage is to use cstdio and fully qualify the symbol names or else bring them in scope with using declarations. This guarantees all symbols we use are present in std namespace and we are not polluting the global namespace. Example of correct usage:

Sample 3:

#include<cstdio>

using std::printf;

int main()
{
    printf("Hello World");
    return 0;
}

Note that the directive using namespace std;, especially in a header, is not a good option and you should always use using declarations.

Note that we consider stdio.h vs. cstdio here just a sample use case, in practice it applies to all most cxxxx and xxxx.h headers, except a few like <math.h> and <cmath>.