- What should I include in C++ programs,
stdio.h
orcstdio
? and Why? - Why two header files which provide the same functionality?
- What does the standard say regarding this?
- How should I go about including other such headers, Is there a base rule that I should follow?

- 202,538
- 53
- 430
- 533
2 Answers
Consider the following programs:
#include<stdio.h>
int main()
{
printf("Hello World");
return 0;
}
#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:
§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:
#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>
.

- 8,409
- 22
- 75
- 99

- 202,538
- 53
- 430
- 533
-
1Just to add to that. If possible, I always try to restrict my use of C headers to the cpp files only (and including them after everything else). I try to avoid including them in any C++ header file. And since C headers do not declare many types (mostly functions), they are usually only needed (if needed at all) in the cpp files. – Mikael Persson Dec 15 '12 at 05:15
-
6-1 re "we are not polluting the global namespace", you have just quoted and discussed that this is not the case. so. a bit of self-contradiction. it is important because it directly affects the conclusion of what is best practice. your conclusion above is wrong. it is *weird*. you first discuss why it's a bad choice (possibility of code not working across compilers, unintended namespace pollution) then you just assert that's "correct usage". which is literally true in that it's not incorrect, but it's a pretty bad choice. – Cheers and hth. - Alf Dec 15 '12 at 05:20
-
@Cheersandhth.-Alf: I fail to understand what you are trying to say.The immediate reason might be that English is not my first language. – Alok Save Dec 15 '12 at 05:32
-
@Alok: please indicate the first word where comprehension failed. – Cheers and hth. - Alf Dec 15 '12 at 06:08
-
@Cheersandhth.-Alf: Sorry for replying late,this just skipped me for some reason.I understand your disagreement stems from the fact that the final solution does not overcome the problems of other practices but it is merely a less bad solution amongst available choices.Can you please edit it appropriately and mark the answer a community edit? or even better can you add your own answer clearly expressing the desired? Eventhough I agree to your objection I am at a little loss of words how to reflect the sentiment in the answer. – Alok Save Jan 10 '13 at 03:19
-
@AlokSave: okay, I'm putting it on the "to do" list. ;-) – Cheers and hth. - Alf Jan 10 '13 at 05:24
-
@Cheersandhth.-Alf: Just happened to visit here when marking a duplicate, gentle reminder for popping this off your to do list. – Alok Save Mar 27 '13 at 10:40
-
@AlokSave: i thought my above statement about "todo-list" was just metaphor, to indicate that i was intending to do something. but now i thought i'd better create a real todo-list. as it turned out in the natural location for such a list there was already one, with exactly one item, namely a link to this answer. so. what does the red string around my thumb mean? – Cheers and hth. - Alf Mar 27 '13 at 11:20
-
1@AlokSave: see [http://stackoverflow.com/a/10694346/464581], including the commentary. quoting steve jossop: "if you include math.h, then you know you're dropping a heap of junk in your global namespace. If you include cmath then you may or may not be dropping a heap of junk in your global namespace. Conversely, you don't care whether or not you drop a heap of junk in namepace std, since you never define symbols in there yourself anyway. So the uncertainty about what math.h does is in some sense better than the uncertainty about what cmath does, regardless of what the committee thinks" – Cheers and hth. - Alf Mar 27 '13 at 13:01
-
-1 for "in practice it applies to all cxxxx and xxxx.h headers" -- some of these headers actually work quite differently, in particular `
`: http://stackoverflow.com/a/8734292/166749 – Fred Foo May 27 '13 at 11:30 -
Alright, undid the -1. Be aware that `
` is also different from ` – Fred Foo May 27 '13 at 11:47` because of various `const` overloads. -
In addition to the quote of D5, you need to quote 17.6.1.2 if you want to prove there's license to declare the symbols in both scopes irrespective which of the two headers is included. – Deduplicator Sep 26 '14 at 19:34
-
4So... the conclusion about the correct usage looks unfounded... Why exactly is using `cstdio`+`std::printf` better than `stdio.h`+`::printf` if in both cases global namespace is potentially polluted so that e.g. creating your own `::printf` function would not be portable? – Ruslan Aug 24 '16 at 15:12
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]
- 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++.
- 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++.
- 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]
- For compatibility with the C standard library, the C++ standard library provides the C headers shown in Table 141.
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.

- 7,935
- 8
- 48
- 83

- 2,199
- 16
- 22
-
3Considering that when I started programming C++11 was still considered a new and major event, the notion that C++17 is barely out the door and people are already considering C++20 is quite amusing. – Pharap Mar 25 '17 at 13:28
-
1@Pharap It's scary and I feel the same. I started with C++03. Then it took 8 years to come up with a new standard. Now, we have C++17 and they're already arguing over C++20. Standards change quicker. It's hard to keep up... – Santiago Varela Mar 25 '17 at 13:33
-
3The Stroustrup article is from ~15 years ago, when the survival of C++ was more closely tied to the popularity of C. It's not clear whether that is as important today. And while it is an interesting question whether to _design the languages_ to be as compatible as possible, I don't see how opinions on that should necessarily guide how we should _write C++ code_. If my code has only ever been tested as C++ code, it seems dubious to strive to keep it compatible with C, especially at the cost of global namespace pollution. – Adrian McCarthy Mar 27 '17 at 20:27
-
For embedded systems development, stdio.h is a header file that you can grep your file system to prove the header file exists. On the other hand, how can we probe the existence in the file system of header files that look like `cstdio` ? Considering the gazillion of compiler variants out there, this smells like trouble in determining the most basics of things on the board. – daparic Sep 24 '18 at 17:24
-
@Pharap why did that happen, and now we're having revisions every few years? – northerner Feb 05 '19 at 07:41
-
1@northerner The original standard was C++98, and then 5 years later they published C++03, which consisted of just a few minor amendments, mostly to the wording of the standard. The next standard was nicknamed "C++0x" because it was originally expected to be published around '08 or '09 (3-4 years after '03), but it kept getting delayed for various reasons and ended up becoming C++11. (Most likely the delay was due to arguments over the number of significant changes being added - the original goal was to focus on improving the standard library.) ... – Pharap Feb 06 '19 at 14:39
-
@northerner As for why they seem to be getting more frequent, I can only guess. It's possible that originally they were supposed to be every few years and C++11 was the exceptional case. Some of the features implemented by C++14, C++17 and C++20 were originally slated for C++11, so it's possible that these started out as attempts to fill in the gaps that were missed and accumulated new suggestions as time went on. Without more research I can't make any definitive claims though, just speculation. (It's worth mentioning that C++14 was another minor revision that only made a few additions.) – Pharap Feb 06 '19 at 14:44