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.
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.
When to use std::size_t?
A good rule of thumb is for anything that you need to compare in the loop condition against something that is naturally a std::size_t
itself.
std::size_t
is the type of any sizeof
expression and as is guaranteed to be able to express the maximum size of any object (including any array) in C++. By extension it is also guaranteed to be big enough for any array index so it is a natural type for a loop by index over an array.
If you are just counting up to a number then it may be more natural to use either the type of the variable that holds that number or an int
or unsigned int
(if large enough) as these should be a natural size for the machine.
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.
Why do I need to use `size_t` in C++?
Its main advantage is that it's the right tool for the job.
size_t
is literally defined to be big enough to represent the size of any object on your platform. The others are not. So, when you want to store the size of an object, why would you use anything else?
You can use int
if you like, but you'll be deliberately choosing the inferior option that leads to bugs. I don't quite understand why you'd want to do so, but hey it's your code.
If you choose to use float
, though, please tell us what program you're writing so we can avoid it. :)
size_t vs int in C++ and/or C
In general, size_t
should be used whenever you are measuring the size of something. It is really strange that size_t
is only required to represent between 0 and SIZE_MAX
bytes and SIZE_MAX
is only required to be 65,535...
The other interesting constraints from the C++ and C Standards are:
- the return type of
sizeof()
issize_t
and it is an unsigned integer operator new()
takes the number of bytes to allocate as asize_t
parametersize_t
is defined in<cstddef>
SIZE_MAX
is defined in<limits.h>
in C99 but not mentioned in C++98?!size_t
is not included in the list of fundamental integer types so I have always assumed thatsize_t
is a type alias for one of the fundamental types:char
,short int
,int
, andlong int
.
If you are counting bytes, then you should definitely be using size_t
. If you are counting the number of elements, then you should probably use size_t
since this seems to be what C++ has been using. In any case, you don't want to use int
- at the very least use unsigned long
or unsigned long long
if you are using TR1. Or... even better... typedef
whatever you end up using to size_type
or just include <cstddef>
and use std::size_t
.
Difference between size_t and unsigned int?
if it is use to represent non negative value so why we not using
unsigned int
instead ofsize_t
Because unsigned int
is not the only unsigned integer type. size_t
could be any of unsigned char
, unsigned short
, unsigned int
, unsigned long
or unsigned long long
, depending on the implementation.
Second question is that
size_t
andunsigned int
are interchangeable or not and if not then why?
They aren't interchangeable, for the reason explained above ^^
.
And can anyone give me a good example of size_t and its brief working ?
I don't quite get what you mean by "its brief working". It works like any other unsigned type (in particular, like the type it's typedeffed to). You are encouraged to use size_t
when you are describing the size of an object. In particular, the sizeof
operator and various standard library functions, such as strlen()
, return size_t
.
Bonus: here's a good article about size_t
(and the closely related ptrdiff_t
type). It reasons very well why you should use it.
Does `sizeof` *really* evaluate to a `std::size_t`? Can it?
Do not confuse the map for the territory.
Types can be named by typenames. These typenames can be built-in, they can be user-defined types, or they could even be template
parameters and refer to multiple different types depending on the instantiation.
But the names are not the types. Clearly standard does not mandate that all types have names -- the classic struct {}
is a type without a name.
std::size_t
is a typename. It names the type that sizeof(expression)
returns.
The compiler could have a canonical name for the type -- __size_t
would be one way for it to have a unique built-in canonical typename.
The standard guarantees in that clause that whatever the type of sizeof(expression)
is, once you #include <cstddef>
, the name std::size_t
now refers to that type.
In the standard, they refer to types by names. They do not say "the type that this typename refers to", but simply say "the type $NAME$". The compiler could decide that int
is another name for __int_32_fast
if it wanted to, and the standard would have no objection either.
This same thing happens with std::nullptr_t
and std::initializer_list<Ts>
and std::type_info
: use of variables of those types does not always require that the header that provides you with a name for those types be included in your program.
The traditional C/C++ built-in types all had canonical names that did not require a header. The downside is that this breaks existing code, as new typenames in the global scope collide with other identifiers.
By having "nameless types", where you can get a name for them via including a header file, we avoid that problem.
Related Topics
Getting a Vector<Derived*> into a Function That Expects a Vector<Base*>
Move Semantics == Custom Swap Function Obsolete
How to Get the Process Name in C++
Need to Call a Function at Periodic Time Intervals in C++
Template Specialization of a Single Method from a Templated Class
How to Generate Assembly Code with Clang in Intel Syntax
Calling the Base Class Constructor from the Derived Class Constructor
Source Code of C/C++ Functions
Converting Data from Glreadpixels() to Opencv::Mat
Enumerating All Available Drive Letters in Windows
How to Make an Array with a Dynamic Size? General Usage of Dynamic Arrays (Maybe Pointers Too)
How to Make Std::Make_Unique a Friend of My Class
Std::Vector Removing Elements Which Fulfill Some Conditions
Why Can't Templates Be Within Extern "C" Blocks
Accessing Protected Members of Superclass in C++ with Templates