Which header should I include for `size_t`?

C++Typedef

C++ Problem Overview


According to cppreference.com size_t is defined in several headers, namely

<cstddef>
<cstdio>
<cstring>
<ctime>

And, since C++11, also in

<cstdlib>
<cwchar> 

First of all, I wonder why this is the case. Isn't this in contradiction to the DRY principle?

Which one of the above headers should I include to use size_t? Does it matter at all?

C++ Solutions


Solution 1 - C++

Assuming I wanted to minimize the functions and types I was importing I'd go with cstddef as it doesn't declare any functions and only declares 6 types. The others focus on particular domains (strings, time, IO) that may not matter to you.

Note that cstddef only guarantees to define std::size_t, that is, defining size_t in namespace std, although it may provide this name also in the global namespace (effectively, plain size_t).

In contrast, stddef.h (which is also a header available in C) guarantees to define size_t in the global namespace, and may also provide std::size_t.

Solution 2 - C++

In fact the synopsis (included in the C++ standard) of several headers specifially include size_t as well as further headers define the type size_t (based on the C standard as the <cX> headers are just ISO C <X.h> headers with noted changes where removal of size_t is not indicated).

The C++ standard however, refers to <cstddef> for the definition of std::size_t

  • in 18.2 Types,
  • in 5.3.3 Sizeof,
  • in 3.7.4.2 Deallocation functions (which refers to 18.2) and
  • in 3.7.4.1 Allocation functions (also refers to 18.2).

Therefore and because of the fact that <cstddef> only introduces types and no functions, I'd stick to this header to make std::size_t available.


Note a few things :

  1. The type of std::size_t is obtainable using decltype without including a header

If you're planning to introduce a typedef in your code anyway (i.e. because you write a container and want to provide a size_type typedef) you can use the global sizeof, sizeof... or alignof operators to define your type without including any headers at all since theose operators return std::size_t per standard definition and you can use decltype on them:

    using size_type = decltype(alignof(char));

2. std::size_t is not per se globally visible although functions with std::size_t arguments are.

The implicitly declared global allocation and deallocation functions

    void* operator new(std::size_t);
    void* operator new[](std::size_t);
    void operator delete(void*);
    void operator delete[](void*);

do NOT introduce size_t, std or std::size_t and

> referring to std or std::size_t is ill-formed unless the name has been declared by including the appropriate header.

  1. The user may not redefine std::size_t although it is possible to have multiple typedefs referring to the same type in the same namespace.

Although, the occurrence of multiple definitions of size_t within std is perfectly valid as per 7.1.3 / 3, it is not allowed to add any declarations to namespace std as per 17.6.4.2.1 / 1:

> The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified.

Adding a proper typedef for size_t to the namespace does not violate 7.1.3 but it does violate 17.6.4.2.1 and leads to undefined behaviour.

Clarification: Try not to misinterpret 7.1.3 and do not add declarations or definitions to std (except a few template specialization cases where a typedef is not a template specialization). Extending the namespace std

Solution 3 - C++

You could do without a header:

using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); //  The shortest is my favourite.
using size_t = decltype(sizeof "anything");

This is because the C++ standard requires:

> The result of sizeof and sizeof... is a constant of type std::size_t. [ Note: std::size_t is defined in the standard header <cstddef> (18.2). — end note ]

In other words, the standard requires:

static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
              "This never fails.");

Also note, that it is perfectly fine to make this typedef declaration in the global and in std namespace, as long as it matches all other typedef declarations of the same typedef-name (a compiler error is issued on non-matching declarations).

This is because:

  • §7.1.3.1 A typedef-name does not introduce a new type the way a class declaration (9.1) or enum declaration does.

  • §7.1.3.3 In a given non-class scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers.


To sceptics saying that this constitutes an addition of a new type into namespace std, and such an act is explicitly prohibited by the standard, and this is UB and that is all there to it; I have to say that this attitude amounts to ignoring and denying deeper understanding of the underlying issues.

The standard bans adding new declarations and definitions into namespace std because by doing so the user may make a mess of the standard library and shoot his entire leg off. For the standard writers it was easier to let the user specialize a few specific things and ban doing anything else for good measure, rather than ban every single thing which the user should not do and risk missing something important (and that leg). They did it in the past when requiring that no standard container shall be instantiated with an incomplete type, while in fact some containers could well do (see The Standard Librarian: Containers of Incomplete Types by Matthew H. Austern):

> ... In the end, it all seemed too murky and too poorly understood; the standardization committee didn't think there was any choice except to say that STL containers aren't supposed to work with incomplete types. For good measure, we applied that prohibition to the rest of the standard library too. > > ... In retrospect, now that the technology is better understood, that decision still seems basically right. Yes, in some cases it's possible to implement some of the standard containers so that they can be instantiated with incomplete types — but it's also clear that in other cases it would be difficult or impossible. It was mostly chance that the first test we tried, using std::vector, happened to be one of the easy cases.

Given that the language rules require std::size_t to be exactly decltype(sizeof(int)), doing namespace std { using size_t = decltype(sizeof(int)); } is one of those things that do not break anything.

Prior to C++11 there was no decltype and thus no way to declare the type of sizeof result in one simple statement without getting a good deal of templates involved. size_t aliases different types on different target architectures, however, it would not be an elegant solution to add a new built-in type just for the result of sizeof, and there are no standard built-in typedefs. Hence, the most portable solution at the time was to put size_t type alias in some specific header and document that.

In C++11 there is now a way to write down that exact requirement of the standard as one simple declaration.

Solution 4 - C++

All standard library header files have the same definition; it does not matter which one you include in your own code. On my computer, I have the following declaration in _stddef.h. This file is included by every file you listed.

/*
   Define the size_t type in the std namespace if in C++ or globally if in C.
   If we're in C++, make the _SIZE_T macro expand to std::size_t
*/

#if !defined(_SIZE_T) && !defined(_SIZE_T_DEFINED)
#  define _SIZE_T_DEFINED
#if defined(_WIN64)
   typedef unsigned __int64 size_t;
#else
   typedef unsigned int size_t;
#endif
#  if defined(__cplusplus)
#    define _SIZE_T std::size_t
#  else
#    define _SIZE_T size_t
#  endif
#endif

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Question463035818_is_not_a_numberView Question on Stackoverflow
Solution 1 - C++SeanView Answer on Stackoverflow
Solution 2 - C++PixelchemistView Answer on Stackoverflow
Solution 3 - C++Maxim EgorushkinView Answer on Stackoverflow
Solution 4 - C++VLLView Answer on Stackoverflow