35

Why is map imported as #include <map>, but stdio imported as #include <stdio.h>?

Casebash
  • 114,675
  • 90
  • 247
  • 350
  • 2
    stdio can also be imported as `#include ` – Matt K Dec 10 '10 at 01:04
  • @Matt: So the import name is different from the filename. How is that done? – Casebash Dec 10 '10 at 01:06
  • @Casebach: There are usually two separate files, `cstdio` and `stdio.h`, with `cstdio` including `stdio.h` in a way that puts all its symbols in namespace std. But the exact way in which it does it depends on the implementation. – Stuart Golodetz Dec 10 '10 at 01:16
  • 1
    @Casebash: No, there actually is a file `cstdio` (or pseudo-file at least, known to the compiler) which defines standard C++ library functions that are *nearly equivalent* to the standard C library header `stdio.h`. – Ben Voigt Dec 10 '10 at 01:18
  • @Stuart: The C++ standard headers can't just include the C headers. Specifically the C headers use `extern "C"` name mangling, which preclude function overloading, and the C++ headers do use overloading. – Ben Voigt Dec 10 '10 at 01:20
  • 1
    @Ben: They might not *just* include the C headers, but on popular compilers (I checked my `cstdio` header on MSVC before answering) they do nevertheless include them. Your point's an interesting one all the same though. – Stuart Golodetz Dec 10 '10 at 01:23
  • @Stuart: Then there must be some magic inside the C header to handle that case. – Ben Voigt Dec 10 '10 at 01:25
  • @Ben: You're right -- it looks like `#ifdef __cplusplus extern "C" { #endif` etc. – Stuart Golodetz Dec 10 '10 at 01:26
  • The point being that `stdio.h` is both a C and C++ standard header. In C++, writing `#include ` includes the 'C-style' C++ header `stdio.h`. In other words, it's a C++ header, but `stdio.h` is the C-style way of writing the include. – Stuart Golodetz Dec 10 '10 at 01:28
  • @Stuart: Actually I was expecting some magic beyond `extern "C"`. The `extern "C"` allows the name to be found in the `std` namespace but still mangle the "C" way, with no namespace and no type information, so the linker can find the function in libc (whatever libc is called on that platform, with Windows it's some variant of msvcrt). But functions which are overloaded require more help than just `extern "C"`. – Ben Voigt Dec 10 '10 at 01:33
  • You could perhaps wonder at the excessive use of .h in C++ for header files as modern IDE don't need that extra info. – Greg Domjan Dec 10 '10 at 02:13
  • @Ben: C functions generally can't be overloaded so there's no problem. Overloading also is unrelated to type-safe linkage. – Yttrill Dec 10 '10 at 03:33
  • @Greg: It's not the IDE that needs that information, it's every other piece of software on the computer, that isn't smart enough to go looking through other text files for `#include` in order to figure out the file type. @Yttrill: The C++ standard library does overload the functions inherited from the C standard library. And while typesafe linkage is good for more than just overloading, they are related. Overloading *requires* type information in the mangled name, because the function identifier by itself doesn't identify the target, the entire signature is required. – Ben Voigt Dec 10 '10 at 04:52

3 Answers3

33

All standard C++ headers don't want the .h in the end. I read somewhere that the concept is that they don't need to be actual files, even if I never saw an implementation do it in another manner edit: actually the compiler intrinsics should work considering the headers included but not actually including them as files; see @Yttrill's comment.

For the stdio.h thing, in a C++ application you shouldn't include <stdio.h>, but you should instead include <cstdio>. In general, you shouldn't include the "normal" C headers, but their C++-ized counterparts, which haven't got the .h in the end, have a c in front and put all the symbols defined in them in the std namespace. So, <math.h> becomes <cmath>, <stdlib.h> becomes <cstdlib>, and so on.

In general, you should use the C++-ized versions of C headers both to avoid to pollute the global namespace (assuming you're not one of those guys who put using namespace std; everywhere) and to benefit of some C++ improvements to the standard C headers (e.g. added overloading to some math functions).


In general, the implementation of this whole thing is simply done by having such files without extension in the directory in which the compiler looks for the header files. In my g++ 4.4 installation, for example, you have:
matteo@teoubuntu:/usr/include/c++/4.4$ ls
algorithm           cstdarg              functional        sstream
array               cstdatomic           initializer_list  stack
backward            cstdbool             iomanip           stdatomic.h
bits                cstddef              ios               stdexcept
bitset              cstdint              iosfwd            streambuf
c++0x_warning.h     cstdio               iostream          string
cassert             cstdlib              istream           system_error
ccomplex            cstring              iterator          tgmath.h
cctype              ctgmath              limits            thread
cerrno              ctime                list              tr1
cfenv               cwchar               locale            tr1_impl
cfloat              cwctype              map               tuple
chrono              cxxabi-forced.h      memory            typeinfo
cinttypes           cxxabi.h             mutex             type_traits
ciso646             debug                new               unordered_map
climits             deque                numeric           unordered_set
clocale             exception            ostream           utility
cmath               exception_defines.h  parallel          valarray
complex             exception_ptr.h      queue             vector
complex.h           ext                  random            x86_64-linux-gnu
condition_variable  fenv.h               ratio
csetjmp             forward_list         regex
csignal             fstream              set

The C++-ized C headers in theory could just be a

namespace std
{
#include <original_C_header.h>
};

but in general they are more complicated to deal with implementation-specific problems (especially regarding macros) and to add C++-related functionality (see e.g. the previous example of added overloads in <cmath>).


By the way, the C++ standard (§D.5) do not say that the <c***> headers should behave as if they included the <***.h> headers in a namespace std directive, but the opposite:

For compatibility with the Standard C library, the C++ Standard library provides the 18 C headers [...] Each C header, whose name has the form name.h, behaves as if each name placed in the Standard library namespace by the corresponding cname header is also placed within the namespace scope of the name-space std and is followed by an explicit using-declaration (7.3.3)

Notice that such headers are considered deprecated (§C.2.1), so this is the main reason you shouldn't use them:

C.2.1 Modifications to headers For compatibility with the Standard C library, the C++ Standard library provides the 18 C headers (D.5), but their use is deprecated in C++.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • 5
    Since Matteo didn't actually provide any reason whatsoever for using the C++ versions of the C standard headers, I'll give one: The C++ headers often provide overloaded versions of the C standard library functions, which are optimized for the actual data type of the arguments. C provides these multiple versions as well, but they all have different names (e.g. `abs` vs `fabs` vs `fabs` vs `fabsl`). It makes a difference with `#include` if you're using templates, and not so much otherwise or for other headers. – Ben Voigt Dec 10 '10 at 01:16
  • @Ben Voigt: funnily, I added it independently in the last revision (after having a quick glance to the `cmath` file) :) – Matteo Italia Dec 10 '10 at 01:19
  • 1
    namespace pollution is actually not much of a reason to use the C++ version of the headers, since no one in their right mind would use naming that conflicts with the C standard library – Ben Voigt Dec 10 '10 at 01:24
  • 2
    @Matteo: of course you did see implementations not using header files, all production compilers including gnu and MS compilers support implementations of functions like memcpy() as intrinsics: the headers may exist as files and contain fallback definitions but that doesn't mean the compiler is actually using them. – Yttrill Dec 10 '10 at 03:35
  • I can't find any interpretation of that new quote that I like, the one that starts "For compatibility". I feel a new question coming on. http://stackoverflow.com/questions/4405887/when-the-c-standard-provides-c-headers-bringing-names-into-the-global-namespace – Ben Voigt Dec 10 '10 at 05:14
  • @Yttrill: you have a point, I stand corrected. – Matteo Italia Dec 10 '10 at 14:17
  • 1
    People should probably know that the *deprecation* is so pedantic and unrealistic that the C++ standard committee even considered undeprecating it, although no conclusion was made for C++20: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0619r3.html#3.5. – Yongwei Wu Aug 06 '18 at 10:19
2

It's simply the name of the actual file on disk. There is (probably) no file called map.h or stdio in your standard include directory.

The C++ standard library moved away from the previous style of using .h toward not having .h at the end of the file names. This may possibly have been related to making the syntax look more like templates:

#include<vector>

vector<int> v;

(Preemptive comment: Yes, I know the above needs std:: to build, but it's just an illustration.)

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • I don't want to downvote a competing answer, but this is actually inaccurate -- there's no guarantee that the files `map` or `stdio.h` exist on disk. – Stuart Golodetz Dec 10 '10 at 01:08
  • That's true, there's no guarantee. Most compilers store the standard library headers as files on disk, though - certainly the popular commonly available ones do. – Greg Hewgill Dec 10 '10 at 01:19
  • Sure - that's the obvious implementation choice. I didn't downvote, just wanted to observe that "it's simply the name of the actual file on disk" isn't strictly accurate as far as the standard goes. – Stuart Golodetz Dec 10 '10 at 01:25
2

It's just the way it's defined by the C++ Standard -- as it happens, map and stdio.h don't even have to be real files.

As a side-note, stdio.h is the header that was originally imported into C++ from the C standard libraries -- the C++ version is cstdio. In practical terms, this generally means that when you include cstdio instead, you get the stuff from stdio.h, but it's in namespace std.

Just to clarify: the stdio.h you include in C++ is the C++ version of what was originally a C header. But the C++ way of writing the include is cstdio.

Stuart Golodetz
  • 20,238
  • 4
  • 51
  • 80
  • 1
    No, `#include` in a C++ program doesn't give you the version from the C standard libraries (or anyway it's not supposed to), see http://stackoverflow.com/questions/4405887/when-the-c-standard-provides-c-headers-bringing-names-into-the-global-namespace – Ben Voigt Dec 10 '10 at 05:44
  • @Ben: Indeed, I phrased this wrong -- I meant to say that it's the C-style way of writing the C++ include, and it doesn't put things in namespace std. – Stuart Golodetz Dec 10 '10 at 10:11