should use size_t or ssize_t

119,980

Solution 1

ssize_t is used for functions whose return value could either be a valid size, or a negative value to indicate an error. It is guaranteed to be able to store values at least in the range [-1, SSIZE_MAX] (SSIZE_MAX is system-dependent).

So you should use size_t whenever you mean to return a size in bytes, and ssize_t whenever you would return either a size in bytes or a (negative) error value.

See: http://pubs.opengroup.org/onlinepubs/007908775/xsh/systypes.h.html

Solution 2

ssize_t is not included in the standard and isn't portable. size_t should be used when handling the size of objects (there's ptrdiff_t too, for pointer differences).

Share:
119,980

Related videos on Youtube

hgyxbll
Author by

hgyxbll

Updated on April 21, 2020

Comments

  • hgyxbll
    hgyxbll about 4 years

    At my code, I do not use int or unsigned int. I only use size_t or ssize_t for portable. For example:

    typedef size_t intc;    // (instead of unsigned int)
    typedef ssize_t uintc;  // (instead of int)
    

    Because strlen, string, vector... all use size_t, so I usually use size_t. And I only use ssize_t when it may be negative.

    But I find that:

    The unsigned integer types are ideal for uses that treat storage as a bit array. Using an unsigned instead of an int to gain one more bit to represent positive integers is almost never a good idea. Attempts to ensure that some values are positive by declaring variables unsigned will typically be defeated by the implicit conversion rules.

    in the book The C++ Programming Language.

    So I am puzzled. Am I wrong? Why does the STL not abide by the suggest on the book?

    • kassak
      kassak about 11 years
      size_t used in standart library for representing sizes. It would be strange if the size of container could be negative. Interface states it's behavior. I think book assumes day-to-day usage, not interface
    • Bo Persson
      Bo Persson about 11 years
      @kassak - No, in this case an unsigned type actually is used to get one extra bit for the value. Some members of the committee saw it important to be able to have a std::vector<char> larger than half the available memory. And the quote says "almost never"...
    • hgyxbll
      hgyxbll about 11 years
      @Bo Persson, thanks, C++ lib use size_t for range. But it brought us the trouble. If we use int, we must be carefull to compare them.
    • chux - Reinstate Monica
      chux - Reinstate Monica over 8 years
      Nominate for re-opening as the duplicate cited does not address this post close enough.
    • RastaJedi
      RastaJedi over 7 years
      Using intc for unsigned size_t (as you say, '[signed] int' in comment, even though it's probably longer), and uintc for signed ssize_t ('unsigned int' in comment), is confusing to me, because normally the 'u' stands for unsigned, e.g. uint32_t is the unsigned version of int32_t, a 4-byte integer.
    • EnzoR
      EnzoR over 6 years
      To those who marked as duplicate. This is definitely not a duplicate. The question is not about signed vs unsigned, but size_t vs ssize_t, that is "when should I use either"?
    • Павел
      Павел almost 4 years
      for (size_t i = a; i < b; i += 2), how many iterations?, a = 0, b = 0xffffffff (32-bit pointers) => infinity loop, for (ssize_t i = a; i < b; i+= 2), how many iterations? (b - a + 1)/2 or none (in case b <= a). Why so? By standart unsigned overflow is well defined and signed overflow is UB (undefined behavior). Compilers some times use UB for optimizations (they assume that several UBs never happen). Some optimizations need to calculate number of loop iterations. From such point of view signed counters is preferrable.
    • hgyxbll
      hgyxbll about 3 years
      now I always use 'int' for most cases, because 'int' is natural, and default a digit's type is 'int', and the range of 'int' is enough for me.
  • hgyxbll
    hgyxbll about 11 years
    I have used ssize_t instead of int. Because CPU handle fast with ssize_t when it is x64.
  • AnT stands with Russia
    AnT stands with Russia over 9 years
    Well, this answer fails to fully explain the consequences of basing such decisions on pure interface considerations. It is unlikely that any implementation will use wider type for ssize_t than it uses for size_t. This immediately means that the price you will pay for the ability to return negative values is halving of the positive range of the type. I.e. SSIZE_MAX is usually SIZE_MAX / 2. This should be kept in mind. In many cases this price is not worth paying just for the ability to return -1 as a negative value.
  • thesaint
    thesaint about 9 years
    @AnT having unsigned values at all is one of the greatest failures in C++. There is no case where the price is not worth paying. If you need such large numbers, use int64_t instead...
  • josaphatv
    josaphatv over 8 years
    @thesaint What the heck are you talking about? It's not about capacity. How would you add four to the stack pointer if its current value may or may not be negative?
  • thesaint
    thesaint over 8 years
    @josaphatv What? How would you add four to the value of the stack pointer if you don't know if that would overflow it? Not to mention that the whole phrase of "adding for to the stack pointer" has nothing to do with C++. Unsigned values are bad because 1) They cause type conversion issues all over the place 2) They add absolutely no benefit 3) They are even less intuitive and predictable than signed ints, since they overflow already at zero. And expression like "while(some_uint - 1 >= 0)" is wrong and hard to spot. Signed overflows are much less likely.
  • thesaint
    thesaint over 8 years
    Besides that your statement makes absolutely no sense. Adding a number to either int or uint is only a matter of wether or not it overflows. If the stack pointer was indeed negative then you have a different problem lol. And even if so, adding something doesn't inherently break anything. Something was broken before. How you think this is any worse than adding four to 0x7FFFFFFF is beyond me (which overflows into kernel space => BOOM).
  • xis
    xis over 8 years
    @hgyxbll What do you mean by ssize_t is faster than int? ssize_t can be either int, or long, it would not be an actual type. I could not understand this, please explain.
  • SlySven
    SlySven over 8 years
    Didn't unsigned integers come about first (prior to signed ones) because of the hardware - obviously this is closer to bare-metal C than most C++ usage but the use of the MSB to allow signed arithmetic was not done just to halve the absolute magnitude that a "integer" could represent but because there was a need for subtractive maths. signed ints and unsigned ints are pears and apples - different but able to cross under certain, limited circumstances...! (Half of the range of each is shared.)
  • SlySven
    SlySven over 8 years
    Where the confusion seems to arise, to me, is when a function that seems it should produce only an unsigned value i.e. the number of bytes that read(2) has been able to actually read. However in the case of an error the value of -1 (probably encoded as ALL bits set) is returned - not to make things difficult but because it is a sentinel value that cannot arise normally.
  • Justin Time - Reinstate Monica
    Justin Time - Reinstate Monica over 7 years
    @thesaint Conversely, if a value cannot be lower than 0, allowing it to be signed is a failure to communicate intent. You can't logically have an array, or other container, of -10 chars, for example (logically, a container with negative size would require the power of creation, because it's so small that it actually increases the number of uncontained objects in its vicinity, creating new ones out of nothing), so it wouldn't make sense to use a signed type for array bounds instead of an unsigned one.
  • Justin Time - Reinstate Monica
    Justin Time - Reinstate Monica over 7 years
    The problem with unsigned types isn't that they exist, it's that they're considered and treated as integers (since all integers, by mathematical definition, are signed); this is directly responsible for people treating them the same as signed types, and by extension for all the problems associated with them. Unsigned types are inherently more predictable (due to having defined overflow behaviour), but a lot of people completely fail to take it into account when checking them because they're used to signed counters (which, IMO, is a failure at teaching, when the counter cannot be less than 0).
  • Justin Time - Reinstate Monica
    Justin Time - Reinstate Monica over 7 years
    Instead of while(some_uint - 1 >= 0) or for(some_uint = 10; some_uint >= 0; --i), a proper check that takes unsigned properties into account would look something like while(some_uint != 0) or for(some_uint = 10; some_uint + 1 != 0; --some_uint). This loop condition works properly regardless of the loop counter's signedness: It ends the loop when some_uint reaches -1, (which is a valid value for signed types, and equal to the maximum storeable value for unsigned types due to overflow/underflow rules); regardless of signedness, -1 + 1 must always equal 0.
  • Justin Time - Reinstate Monica
    Justin Time - Reinstate Monica over 7 years
    The while loop works because: For some_uint - 1 to be >= 0, some_uint must logically be >= 1; therefore, once some_uint == 0, and is thus no longer >= 1, some_uint - 1 can no longer be >= 0, and the loop is terminated. The for loop works on the same principle: For some_uint to be >= 0, some_uint + 1 must be >= 1; therefore, once some_uint + 1 == 0, and is thus no longer >= 1, some_uint can no longer be >= 0, and the loop is terminated. Simple, well-defined, and makes perfect sense if one knows how unsigned types work.
  • Justin Time - Reinstate Monica
    Justin Time - Reinstate Monica over 7 years
    Alternatively, it could be written to specifically check for static_cast<decltype(some_uint)>(-1); this is more verbose, but communicates intent more clearly.
  • Kafu
    Kafu over 7 years
  • dtouch3d
    dtouch3d over 7 years
    The type ssize_t has a range of [-SSIZE_MAX, SSIZE_MAX], not [-1, SSIZE_MAX].
  • Patrick Fromberg
    Patrick Fromberg about 4 years
    Supporters of unsigned sizes do not understand two things. One is, that they implicitly advocate for unsigned arithmetic which is totally broken for calculating sizes (also in terms of perforamance). The second thing they may not understand is a bit more subtle (to complicated for me I admit) but here is an example. In transportation they give negative waiting times for events all the time. Negative waiting times are not an error in this case but a useful concept similar to imaginary numbers. BTW, not sure, but was there ever a discussion about negative numbers in book keeping?
  • Swift - Friday Pie
    Swift - Friday Pie almost 4 years
    C++11 and later implements template std::make_signed, but it's somewhat grey area if using size_t as its parameter is well-defined. In c++20 use of this template with types not allowed by standard results in ill-formed code, but existing implementations allow use of size_t
  • Tom Lint
    Tom Lint over 2 years
    @PatrickFromberg what's broken about using unsigned arithmetic for calculating sizes? I've never seen a negative size. You?
  • Patrick Fromberg
    Patrick Fromberg over 2 years
    @TomLint, what is broken is that 1-2 equals some hardware dependent arbitrary looking number when using arithmetic operators on unsigned numbers. There are some exotic uses for that, but most of the time this is not the result that you want. int main () {unsigned int a = 1, b = 2; std::cout << (a-b) << std::endl;}