Should I include stddef.h or cstddef for size_t

16,245

Solution 1

I prefer #include <stddef.h>.

Some of the names in the C headers are allowed to be macros, but the set differs from the C rules. In C, EXIT_FAILURE, isdigit(), getc() a.o. are macros. Do you know which ones are macros in C++?

Secondly, only a couple standard C headers are required to have the <cfoo> header, Posix headers are not. Do you know which headers are standard and which ones are provided by your compiler only?

Thirdly, when using headers from a third-party C library, you will end up with #include <stddef.h>, and I prefer not to mix <stddef.h> and <cstddef>.

Fourthly, the current draft for the new C++ standard says that <cstdlib> is allowed to dump the symbols into the global namespace (because apparently many compilers already do so nowadays), so using #include <cstdlib> is not a guarantee that the global namespace will be unpolluted in the future. So I would advice that when writing portable code, you should assume the global namespace will be affected (even though it is not allowed now). As only a few experts seem to know this (see the discussion in the comments here), it is better to use <stddef.h> as even a beginning C++ programmer will understand that it pollutes the global namespace.

Solution 2

stddef.h is the C header. The name size_t is in global namespace in it. <cstddef>, on the other hand, is a C++ header which wraps the C names into std namespace, which is naturally the C++ approach, so if you include <cstddef> and the compiler is compliant you'll have to use std::size_t . Clearly, in C++, C++ approach is more appropriate.

Technically, the C header too may contain the names in the std namespace. But the C-headers (those that end with .h) introduce the names also to the global namespace (thus polluting it).

Solution 3

<stddef.h> is officially a deprecated part of C++ (along with the rest of Annex D of the C++ standard). All of these are (non-deprecated) parts of Standard C, so even though they're deprecated in C++, they're virtually certain to remain available almost indefinitely.

A lot of features that aren't deprecated will almost certain disappear first -- export is already gone from the current draft of C++0x, and if I had to guess, I'd say exception specifications were a lot more likely to go than Annex D. When/if these headers do become truly obsolete, it'll probably be from a mature version of David Vandervoorde's modules proposal, which could easily render all headers obsolete.

At the same time, a fair number of compilers (especially older ones) don't implement the <c*> headers exactly the way the standard prescribes. If you want/need to write code that works with them, you gain quite a bit by using the <*.h> headers instead of the <c*> headers.

Ultimately, I think the <c*> headers were a solution in search of a problem. The C standard requires that these headers only define the names that are required -- no others at all except names that are reserved, such as with a leading underscore followed by another underscore or a capital letter. The reserved names (and a few more) are reserved in C++ as well, so they can't collide with anything in portable code in any case. As such, all the <c*> headers buy you is the ability to define a name in the global namespace that collides with an existing name in the C standard library. That is such a spectacularly awful idea that it's not even worth considering doing, so from a practical viewpoint you've gained nothing.

Edit: Even that useless capability worked with few enough real compilers that the current drafts of the up-combing C++0x give permission for the <c*> headers to pollute the global namespace anyway, so even the theoretical advantage is gone.

Solution 4

Both are in the standard and, AFAIK, there to stay.

The form cXXX always introduces the names in the std namespaces, the form XXX.h always introduces the names in the global namespace. Both may also put the names in the other namespace (at least in C++0X, it wasn't the case previously. As respecting that constraint make it impossible to build a C++ library from a C library you don't control, the constraint was removed. g++ suffers of that problem at least on the non glibc targets).

For traditional Unix headers, in all implementation I've tested the form XXX.h includes the additional Unix identifier if you have the needed feature macros defined before. The behavior for the form cXXX was inconsistent between implementations. So in practice I use the XXX.h as I often need those declarations.

Share:
16,245
fredoverflow
Author by

fredoverflow

Updated on June 06, 2022

Comments

  • fredoverflow
    fredoverflow about 2 years

    When I want to use size_t in C++, should I include <stddef.h> or <cstddef>? I have heard several people saying that <cstddef> was a bad idea, and it should be deprecated. Why is that?

  • BЈовић
    BЈовић over 13 years
    Which paragraph exactly in the c++ standard tells that?
  • Puppy
    Puppy over 13 years
    @VJo: I have no idea, and don't quote paragraph about anything that's Standard. But I know that it is. Someone else is the Standard bible. I'll ask them.
  • paxdiablo
    paxdiablo over 13 years
    Good call. While stddef.h (and 17 other C headers) are _specifically part of C++03, they infect the global namespace and you should be, as you say, using C++ rather than the compatibility functions - C++ also provides malloc but no sane C++ programmer would use it :-)
  • paxdiablo
    paxdiablo over 13 years
    stddef.h is explicitly mentioned in C++03, the current standard. See Armen's answer for the reason why you shouldn't use them but they're definitely part of ISO C++.
  • Sjoerd
    Sjoerd over 13 years
    <stddef.h> must define size_t in std:: and adds an using std::size_t;
  • Philipp
    Philipp over 13 years
    §D.7/1: “For compatibility with the C standard library and the C Unicode TR, the C++ standard library provides the 25 C headers, […]”; that means <stddef.h> is part of the C++ standard, but deprecated.
  • Philipp
    Philipp over 13 years
    @Sjoerd: §D.7/2 says: “It is unspecified whether these names are first declared or defined within namespace scope (3.3.6) of the namespace std and are then injected into the global namespace scope by explicit using-declarations (7.3.3).”
  • paxdiablo
    paxdiablo over 13 years
    Sorry, Armen, I'd already added that bit to the first paragraph :-) Hope you don't mind.
  • Philipp
    Philipp over 13 years
    Also see the example in §D.7/3: “It [the header <stdlib.h>] may also provide these names within the namespace std.” (emphasis added)
  • Sjoerd
    Sjoerd over 13 years
    @Philipp Thanks for the standard quotes!
  • Philipp
    Philipp over 13 years
    @Armen: No, stddef.h doesn’t need to provide std::size_t (and in fact, it doesn’t provide it when compiling with G++ 4.4.3).
  • Sjoerd
    Sjoerd over 13 years
    +1 for mentioning the inconsistency of <cXXX> implementations, which historically was for me the most compelling reason.
  • Philipp
    Philipp over 13 years
    I severely doubt that stddef.h will ever be banned, but technically, it's permitted because the standard says: "These are […] not guaranteed to be part of the Standard in future revisions".
  • paxdiablo
    paxdiablo over 13 years
    The current standard states in D5/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 also placed within the namespace scope of the namespace std and is followed by an explicit using-declaration". This may be changing in C++0x (I don't know) but I think this answer is correct based on that.
  • Philipp
    Philipp over 13 years
    @pax: That would mean that G++ breaks the current standard, right? Maybe that was the reason why it was changed.
  • AProgrammer
    AProgrammer over 13 years
    @Philipp, there are things which were not mentioned in such a clause which were removed, and things which are which is staying along...
  • paxdiablo
    paxdiablo over 13 years
    gcc has things like -std=c99 so I doubt that g++ breaks the standard, it's just you may have to select the right flags.
  • Armen Tsirunyan
    Armen Tsirunyan over 13 years
    @Philipp: Which is exactly the definition of the term "deprecated" :)
  • Philipp
    Philipp over 13 years
    @pax: I've tested it with -pedantic and with both -std=c++98 and -std=c++0x (there is no C++03 in G++ 4.4.3), with the same result. #include <stddef.h> simply seems to include the C file stddef.h that has no provisions for C++.
  • Sjoerd
    Sjoerd over 13 years
    @Philipp Correct, gcc was/is non-compliant on this point. I've won several bets with C++ programmers on this point as they rely too much on gcc being always correct :).
  • Philipp
    Philipp over 13 years
    @Armen: Exactly what I've quoted, see §D/2: "… where deprecated is defined as: Normative for the current edition of the Standard, but not guaranteed to be part of the Standard in future revisions."
  • Sjoerd
    Sjoerd over 13 years
    See this link for some quotes and additional links: stackoverflow.com/questions/2587445/…
  • Philipp
    Philipp over 13 years
    @Sjoerd: The problem is that the C++ standard isn't publicly available, so one often has to trust the compiler. Indeed I'm quite surprised about such a bug. Is there no bug report yet?
  • Sjoerd
    Sjoerd over 13 years
    @philipp Almost every line of the C++ standard has been quoted in some C++ discussion, so google can be useful. Even the Wikipedia article mentions this point: en.wikipedia.org/wiki/…
  • Sjoerd
    Sjoerd over 13 years
  • Sjoerd
    Sjoerd over 13 years
    @Armen Technically, the C++ header may contain the names in the global namespace, so pollution can never be ruled out.
  • Jerry Coffin
    Jerry Coffin over 13 years
    <cstdlib> is not "allowed to dump the symbols into the blobal namespace. (§17.4.1.2/4): "In the C++ Standard Library, however, the declarations and definitions (except for names which are defined as macros in C) are within namespace scope (3.3.5) of the namespace std."
  • Sjoerd
    Sjoerd over 13 years
    It's even worse than you descibe: The <c*> headers are allowed to put the names into the global namespace, thus the <c*> headers don't even buy you the ability to define a name in the global namespace that collides with an existing name in the C standard library.
  • Jerry Coffin
    Jerry Coffin over 13 years
    @Sjoerd: See my comment to your (incorrect) reply saying the same. It's true that many implementations do that, but it's not allowed by the current standard.
  • Jerry Coffin
    Jerry Coffin over 13 years
    @Philipp: the problem is that this is no different from any other part of the standard -- nothing is guaranteed to be in a future version of the standard, even if it's not deprecated (e.g., export).
  • Jerry Coffin
    Jerry Coffin over 13 years
    @Philipp: the C++ standard certainly is publicly available (though not free). Drafts of the standard are also available, and are free (and the final draft rarely differs from the real standard enough for most people to notice or care).
  • Sjoerd
    Sjoerd over 13 years
    @Jerry See the latest version of the (future) C++0x at open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#456 Quote: "[Example: The header <cstdlib> assuredly provides its declarations and definitions within the namespace std. It may also provide these names within the global namespace. [..]"
  • Sjoerd
    Sjoerd over 13 years
    The proposed wording of C++0x allows it, see open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#456 .
  • Jerry Coffin
    Jerry Coffin over 13 years
    @Sjoerd: yes, that may (probably will) eventually happen -- but it's not currently allowed.
  • Philipp
    Philipp over 13 years
    @Jerry: The latest draft for C++03 isn't freely available either, so I'm always quoting from the latest C++0x draft, where the behavior was changed.
  • Philipp
    Philipp over 13 years
    @Sjoerd: Thanks for the links, but unfortunately the Wikipedia page says "should" instead of "shall."
  • Bo Persson
    Bo Persson over 13 years
    It is not something that will eventually happen, it is what almost all compilers already do. That's why the standard was changed, to allow existing practice! Most C++ compilers will have to use the .h headers from the system C compiler, whether they like it or not.
  • Jerry Coffin
    Jerry Coffin over 13 years
    @Philipp: That's true (unfortunately). For the current standard, it's probably more accurate to look at: open-std.org/jtc1/sc22/open/n2356. That's the final draft of the 1998 standard, but the changes in '03 were relatively minor.
  • Philipp
    Philipp over 13 years
    @Jerry: I agree, the usage of "deprecated" is quite vague. I think export could have been removed because most major compilers didn't implement it. "Deprecated" seems to be more of a wish than a definition. On the other hand, I'm not convinced that including the C header is actually preferable—at least it's inconsistent.
  • Sjoerd
    Sjoerd over 13 years
    @Bo Editted the text once more. Maybe I should refactor my text after all the bug-fixes?! :P
  • Adrian McCarthy
    Adrian McCarthy over 11 years
    Most of the reasons you list sound like arguments for preferring <cstddef>.