69

As title: is size_t always unsigned, i.e. for size_t x, is x always >= 0 ?

peterchen
  • 40,917
  • 20
  • 104
  • 186
  • 1
    Possible duplicate of [unsigned int vs. size\_t](https://stackoverflow.com/q/131803/608639) – jww Mar 19 '19 at 03:01
  • **If you end up here, there's a good chance you're looking for [`ptrdiff_t`](https://en.cppreference.com/w/cpp/types/ptrdiff_t) (or [`intrptr_t`](https://en.cppreference.com/w/cpp/types/integer)).** ("For char arrays shorter than `PTRDIFF_MAX`, `std::ptrdiff_t` acts as the signed counterpart of `std::size_t`: it can store the size of the array of any type and is, on most platforms, synonymous with std::intptr_t. ") See also: https://stackoverflow.com/q/35071200/1599699 – Andrew Nov 15 '20 at 09:41
  • 1
    `ssize_t` is not a signed `size_t`. It is only guaranteed to support a signed value of -1, and while it might work on Posix, it is an unsigned type on Windows. – Dwedit Oct 22 '21 at 21:30

6 Answers6

57

Yes. It's usually defined as something like the following (on 32-bit systems):

typedef unsigned int size_t;

Reference:

C++ Standard Section 18.1 defines size_t is in <cstddef> which is described in C Standard as <stddef.h>.
C Standard Section 4.1.5 defines size_t as an unsigned integral type of the result of the sizeof operator

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • @Neil: I know. It was the first thing I found. I don't have C++ standard at hand so I'm downloading it (my connection is damn slow). In the meantime, I put something other than myself. – Mehrdad Afshari Jul 06 '09 at 21:08
  • Well, I do have the C++ standard to hand, but can't find it, possibly because it's actually defined in the C (not C99) standard. I am hoping someone will track it down, because I think its an interesting question! –  Jul 06 '09 at 21:12
  • Be aware that cplusplus.com has some weird sites. Look at this, for example: http://www.cplusplus.com/reference/iostream/ostream/operator%3C%3C/ now that are fun signatures of operator<< :) – Johannes Schaub - litb Jul 06 '09 at 21:13
  • @Neil: True. I'm hunting for C standard now. – Mehrdad Afshari Jul 06 '09 at 21:14
  • @litb: Yeah. It's not reliable but for this specific case, I was pretty sure that `operator new` is defined using `size_t` as a parameter so it should be unsigned. – Mehrdad Afshari Jul 06 '09 at 21:15
  • operator new is, and AFAICT size_t is not defined in the C++ standard. – David Thornley Jul 06 '09 at 21:22
  • @Neil: Not the actual standard but pretty much explains it http://www.lysator.liu.se/c/rat/c3.html#3-3-3-4 : The Standard, like the Base Document, defines the result of the `sizeof` operator to be a constant of an unsigned integral type. *and also*: The type of `sizeof`, whatever it is, is published (in the library header ``) as `size_t` – Mehrdad Afshari Jul 06 '09 at 21:23
  • 2
    Thanks mehrdad for hunting down the reference – peterchen Jul 06 '09 at 21:38
  • 12
    please note that `size_t` will normaly be 64 bit on 64 bit systems, whereas `int` might still be 32 bit; such things are highly compiler specific – Christoph Jul 06 '09 at 23:27
  • Christoph: That's exactly why emphasis is added on the word *usually*. I wrote that line of code to demonstrate the idea, not to rely on. – Mehrdad Afshari Jul 06 '09 at 23:39
  • 2
    @litb: C++2003, 27.6.2.5.2 defines those signatures. Note that the first block are member functions (thus not first basic_ostream& argument) while the last block are free functions.@Mehrdad: C++2003, 5.3.4 par 10: A new-expression passes the amount of space requested to the allocation function as the first argument of type std::size_t, same as in http://www.cplusplus.com/reference/std/new/operator%20new/ – David Rodríguez - dribeas Jul 07 '09 at 05:24
53

According to the 1999 ISO C standard (C99), size_t is an unsigned integer type of at least 16 bit (see sections 7.17 and 7.18.3).

The standard also recommends that size_t shouldn't have an integer conversion rank greater than long if possible, ie casting size_t to unsigned long is unproblematic if the recommendation is followed.

The 1989 ANSI C standard (ANSI C) doesn't mention a minimal size or recommended conversion rank.

The 1998 ISO C++ standard (C++98) (as well as the current draft for C++0x) refers to the C standard. Section 18.1 reads:

The contents are the same as the Standard C library header <stddef.h> [...]

According to section 1.2, this means the library as defined by the 1990 ISO C standard (C90), including its first amendment from 1995 (C95):

The library described in clause 7 of ISO/IEC 9899:1990 and clause 7 of ISO/IEC 9899/Amd.1:1995 is hereinafter called the Standard C Library.

The parts regarding size_t should be inherited from ANSI C: Frontmatter and section numbering aside, the standards for C90 and ANSI C are identical. I'd need a copy of the normative amendment to be sure that there weren't any relevant changes to stddef.h, but I doubt it. The minimal size seems to be introduced with stdint.h, ie C99.

Please also consider the following quote from section 1.2 of C++98:

All standards are subject to revision, and parties to agreements based on this International Standard are encouraged to investigate the possibility of applying the most recent editions of the standards indicated below.

Christoph
  • 164,997
  • 36
  • 182
  • 240
  • Unfortunately, the question isn't about C99 but C++. –  Jul 06 '09 at 21:08
  • 10
    @Neil, well he has to take the C Standard, because the C++ Standard delegates to it :) It doesn't itself define size_t :) – Johannes Schaub - litb Jul 06 '09 at 21:11
  • 2
    Yes, but the C++ standard doesn't reference the C99 standard. –  Jul 06 '09 at 21:13
  • 1
    Somehow i believed the C89/C95 Standard required size_t to be at least 16 bit. But it looks like only C99 has that requirement and that it's at least 65535. – Johannes Schaub - litb Jul 06 '09 at 21:41
  • @Neil: Actually, the C++ standard never mentions to which version of ISO C it refers; and ISO/IEC 9899:1990 is officially withdrawn – Christoph Jul 06 '09 at 21:53
  • 2
    It says it references C99, but for the library, it refers to C90 and C95. In 1.2/2 it says "The library described in ... C90 and in ... C95 is here-inafter called 'The Standard C Library'". Thus when it specifies the content of cstddef, it refers to C89 (and the amendment C95, which is a TC to C89 afaik. As is C++03 to C++98 too) (another time specified by 17.4.1.2/4) – Johannes Schaub - litb Jul 06 '09 at 22:50
  • @litb: you're right, thanks; I only did a quick search and somehow didn't find the normative references; will edit some more – Christoph Jul 06 '09 at 22:59
  • "ie casting size_t to unsigned long is unproblematic if the recommendation is followed." that reccomendation only applies if long is large enough. In particular on win64 long is smaller than size_t. – plugwash Apr 05 '23 at 17:46
13

Yes, size_t is guaranteed to be an unsigned type.

nos
  • 223,662
  • 58
  • 417
  • 506
  • 1
    This is not considered a good answer (anymore). Just a statement is not a real answer, some kind of justification seems required. – Maarten Bodewes Apr 07 '20 at 14:12
6

According to the standard it is unsigned, however I recall that some older implementations used a signed type for the typedef.

From an older GCC doc:

There is a potential problem with the size_t type and versions of GCC prior to release 2.4. ANSI C requires that size_t always be an unsigned type. For compatibility with existing systems' header files, GCC defines size_t in stddef.h to be whatever type the system's sys/types.h defines it to be. Most Unix systems that define size_t in sys/types.h, define it to be a signed type. Some code in the library depends on size_t being an unsigned type, and will not work correctly if it is signed

I'm not sure how important it would be to guard against that. My code assumes it's unsigned.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • I think everyone knows it's probably unsigned - but unless someone can quote a relevant standards document, we'll never know for sure. –  Jul 06 '09 at 21:10
  • I don't have the standard document handy at the moment (though I'm confident that all the relevant standards, C90, C99 and C++98 and beyond require it to be unsigned). However, I just wanted to point out that regardless of the standard, there are potentially important exceptions where size_t is a signed type. – Michael Burr Jul 06 '09 at 21:14
  • There have now been answers to this question that do quote C99. However, it might be a good idea to leave this answer for those that run into unexpected issues with (older) compilers / base libs. – Maarten Bodewes Apr 07 '20 at 14:13
3

The size_t should follow the same definition as the C standard, and in several places in the C++ standard it implies it's unsigned natura (particularly in the allocator template argument definitions).

On the C++ Standard, section 18.1 (ISO/IEC 14882 - First edition 1998-01-01):

Table 15 lists as defined types: ptrdiff_t and size_t

3 The contents are the same as the Standard C library header , with the following changes: 4 The macro NULL is an implementation-defined C++ null pointer constant in this International Standard (4.10).

The macro offsetof accepts a restricted set of type arguments in this International Standard. type shall be a POD structure or a POD union (clause 9). The result of applying the offsetof macro to a field that is a static data member or a function member is undefined. SEE ALSO: subclause 5.3.3, Sizeof, subclause 5.7, Additive operators, subclause 12.5, Free store, and ISO C subclause 7.1.6.

njsf
  • 2,729
  • 1
  • 21
  • 17
2

Oh, this is just terrible:

vector<MyObject> arr;
Fill(arr);
size_t size = arr.size();
for(size_t i = 1; i < size - 1; ++i)
{
  auto obj = arr[i];
  auto next = arr[i+1];
}

Now contemplate the use case where arr is empty.

  • 1
    Yes it is. But can you show me an idiomatic way how the above code can be made correct? And strictly speaking it's not an answer to OP's question. – user643011 Oct 16 '18 at 10:47