Should I Include Stddef.H or Cstddef for Size_T

Should I include stddef.h or cstddef for size_t

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.

Which header should I include for `size_t`?

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.

C++ size_t doesn't need cstddef header?

size_t is really a grey area. std::size_t is the result type of sizeof, but sizeof is a built-in operator you can use without any #include at all. Consider this complete little program:

// no includes, no using namespace std

int main()
{
auto x = sizeof(int); // x is std::size_t
}

On top of that, Visual C++ has always behaved a bit strangely here. Even with settings like /permissive- /std:c++latest in the newest version of the compiler, it still allows the following illegal code:

// no includes, no using namespace std

int main()
{
size_t i = 0;
}

In fact, it would even allow this:

// no includes, no using namespace std

int main()
{
int ar[10];

for (size_t x = 0; x < 10; ++x)
ar[x] = x;

for (auto a : ar)
;

return 0;
}

Nevertheless, what others said about the indirect inclusion of headers is correct. To be precise, the C++ standard says the following about standard-library headers at §20.5.5.2:

A C++ header may include other C++ headers.

Which means that Visual C++ behaves correctly in your case anyway. Once you include <iostream>, the implementation is free to indirectly include one of the six standard C++ headers that define std::size_t, and your using namespace std; (which is evil) does the rest.

The C++ standard even guarantees some of such indirect inclusions, but this isn't one of them, so in order to make your code compatible with other compilers, you are strongly encouraged to include <cstddef> or one of the others that guarantee std::size_t.

Why can I use size_t and std::size_t in MSVS without the traditional headers?

Strictly speaking your code is illegal. The size_t type is required to be declared in the following headers:

<cstddef>
<cstdio>
<cstdlib>
<cstring>
<ctime>
<cwchar>

But also the standard allows standard headers to include other standard headers. So most likely the header <vector> in the standard library used by MSVC includes one of the headers above. This is allowed, but not mandated by the standard so this will work on your setup, but can fail to work on other standard library implementations, even on a future version of the same one you are using.

So in conclusion try to include all the headers required by the standard for all the definitions you are using.

IMHO this is a faulty behavior, but is the required price C++ pays for backward compatibility to the inclusion system that seemed a reasonable design many years ago. The limitations and drawbacks of this are well known today and so the committee is working on modules, which is a modern alternative to the current inclusion mechanism.


As to why you can use size_t without std:::

<cstddef> is required to declare std::size_t and may also optionally declare (or bring in the declaration of) size_t in the global scope.

<stddef.h> is a C backward compatible header and it declares size_t at the global scope.

So either <cstddef> declares size_t at a global level and is included by <vector> or <stddef.h> is included by <vector> - most likely indirectly via <cstddef>.

https://stackoverflow.com/a/283023/2805305

Should I always include stddef.h if I use sizeof and size_t

sizeof(), while looking like a function call, is actually an operator and part of the language core. No include needed.

size_t is defined in various headers: stddef.h, string.h, stdlib.h, and stdio.h. Including any one of them is enough to use size_t in your code.

Does std::size_t make sense in C++?

There seems to be confusion among the stackoverflow crowd concerning this

::size_t is defined in the backward compatibility header stddef.h . It's been part of ANSI/ISO C and ISO C++ since their very beginning. Every C++ implementation has to ship with stddef.h (compatibility) and cstddef where only the latter defines std::size_t and not necessarily ::size_t. See Annex D of the C++ Standard.

What to do with size_t vs. std::size_t?

You should specify it with the using directive.

using std::size_t;

Add it either to the global scope of each compilation unit, or to the local scopes if it would cause interference at the global scope.

stddef.h also works, as you noted, and honestly that method is not "worse" than this one. However, stddef.h is a backwards compatibility header, and it might be best to avoid relying on it in new code.

I prefer the using directive because it does not pollute the global namespace anywhere you don't need to, and does not rely on arbitrary compiler support of nonstandard behavior. Further, this is the generally accepted way to bring a type into a namespace when multiple options are otherwise possible, so it is not unique to the usage of size_t.

This isn't really something that a person can authoritatively answer. I've been a professional developer for 10 years, and have worked with C++ since 1998, but I will never see any statistically significant portion of the total C++ code that's been written. From what I have seen, there is plenty of code out there that still uses stddef.h, and it won't likely break anytime soon.

For new code, I prefer just typing the "std::" prefix everywhere, only applying the using directives when it becomes cumbersome or difficult to read. However, I recognize that this can be irritating for "inherited" code, which is where the file-scope using directives are better. If you have the time to properly refactor the inherited code, there's a good argument that you should do so, but it's very likely to involve more than just the size_t variables.

I should also mention that the C++ FAQ (item 27.5) mentions this concern as well here, where I got the impression they mostly recommend consistency with others on your team.

I want to note here that it is NOT good practice to apply "using namespace std" at the file scope, though this would also bring size_t into the global namespace. I will link the reason for that here.

I seem to have scared tuple_cat off (sorry), but I really did think his empirical method was good, so I'm trying to incorporate some changes to resolve my concerns with his answer. I tried searching github with the following modified queries, which admittedly still may have some issues:

A) "size_t" AND "stddef.h" language:c++
B) "std::size_t" AND "<cstddef>" language:c++
C) "size_t" AND "<cstddef>" AND NOT "std::size_t" language:c++
D) "size_t" AND "<cstddef>" AND "using namespace std" AND NOT "std::size_t" language:c++
E) "size_t" AND "<cstddef>" AND "using std::size_t" language:c++

I get the following:

  • A) 974,239 results (stddef.h approach)
  • B) 1,230,021 results (cstddef approach, with "std::" prefixes)
  • C) 469,721 results (cstddef approach, no prefixes)
  • D) 32,539 results (cstddef approach, "using namespace std", DON'T DO THIS!)
  • E) 27,080 results (method I recommend, "using std::size_t")

It's definitely not perfect, and I welcome criticism to make it better, but it appears that the method I recommend, as stated, is not the most popular. Based on the data, it appears that the most popular is using the "std::" prefixes on size_t (B), followed by including "stddef.h" (A). Luckily, the bad approach of (D) is not popular, but it appears that many people may be relying on other files/headers to bring size_t into the global namespace, or just hoping it's already there on the compiler (C).

Therefore, to "go with the herd", you should prepend everything with "std::". If you don't want to do that, then "stddef.h" is also in very common use, but my preference is still the using directive.

Where is size_t Defined?

I presume this technically means that the definition of size_t in the global namespace has been deprecated?

Yes... but.

The Standard only mandates that std::size_t must be defined1 by <cstddef>, it does not disallow an implementation to define ::size_t2, but if the implementation does, the two definitions must match3.

As a conclusion, you should use std::size_t and should neither rely on ::size_t to be defined nor define it.

The following are UB:

// DON'T
using size_t = std::size_t; // UB
using size_t = decltype(sizeof 1); // UB

1) [cstddef.syn]

namespace std {
using ptrdiff_­t = see below;
using size_­t = see below;
using max_­align_­t = see below;
using nullptr_­t = decltype(nullptr);

[...]

The contents and meaning of the header <cstddef> are the same as the C standard library header <stddef.h>, except that it does not declare the type wchar_­t, that it also declares the type byte and its associated operations ([support.types.byteops]), and as noted in [support.types.nullptr] and [support.types.layout].

2)[extern.types]/1

For each type T from the C standard library (These types are [...] size_­t,[...].), the types ​::​T and std​::​T are reserved to the implementation[.]

3)[extern.types]/1

[...] when defined, ​::​T shall be identical to std​::​T.

Difference between size_t and std::size_t

C's size_t and C++'s std::size_t are both same.

In C, it's defined in <stddef.h> and in C++, its defined in <cstddef> whose contents are the same as C header (see the quotation below). Its defined as unsigned integer type of the result of the sizeof operator.

C Standard says in §17.7/2,

size_t which is the unsigned integer type of the result of the sizeof operator

And C++ Standard says (about cstddef header) in §18.1/3,

The contents are the same as the Standard C library header , with the following changes.

So yeah, both are same; the only difference is that C++ defines size_t in std namespace.

Please also notice that the above line also says "with the following changes" which isn't referring to size_t. Its rather referring to the new additions (mostly) made by C++ into the language (not present in C) which are also defined in the same header.


Wikipedia has very good info about range and storage size of size_t:

Range and storage size of size_t

The actual type of size_t is
platform-dependent; a common mistake
is to assume size_t is the same as
unsigned int, which can lead to
programming errors,[3][4] when moving
from 32 to 64-bit architecture, for
example.

According to the 1999 ISO C
standard (C99), size_t is an unsigned
integer type of at least 16 bits.

And the rest you can read from this page at wikipedia.



Related Topics



Leave a reply



Submit