Question

size_t is declared as unsigned int so it can't represent negative value.
So there is ssize_t which is the signed type of size_t right?
Here's my problem:

#include <stdio.h>
#include <sys/types.h>

int main(){
size_t a = -25;
ssize_t b = -30;
printf("%zu\n%zu\n", a, b);
return 0;
}

why i got:

18446744073709551591
18446744073709551586

as result?
I know that with size_t this could be possible because it is an unsigned type but why i got a wrong result also with ssize_t??

Was it helpful?

Solution

In the first case you're assigning to an unsigned type - a. In the second case you're using the wrong format specifier. The second specifier should be %zd instead of %zu.

OTHER TIPS

First of all you should check the actual size of the two types. Something like the following snippet should do:

#include <stdio.h>
#include <unistd.h>

int main() {
  printf( "sizeof(  size_t ) = %d bytes\n",(int) sizeof( size_t) );
  printf( "sizeof( ssize_t ) = %d bytes\n",(int) sizeof( ssize_t) );
  return 0;
}

I get (64bit Linux, GCC v7.2) "8 bytes" in both cases, which is the same as long int and long long int, the maximum CPU-native integer value.

When the sizes are the same (and they should always be), size_t can have "2x larger absolute values" than ssize_t which, in turn, can have signed (that's either positive or negative) values.

If they were different, then the larger one would be ... larger and could thus accommodate for larger values.

But in the end, ssize_t and size_t are two different types used to "talk" about sizes, lengths, amounts of memory and so on.

The former is just ditching 1 bit for the value in order to gain the sign needed to signal some sort of error.

Finally, the two types are not interchangeable, not always at least. When the size can go past 2^63 bytes/items the difference is clear. size_t won't overflow while ssize_t will.

Under "normal" circumstances you can cast from one to the other one. For the cases I mentioned earlier, you should never mix them.

Just as a reference, both strlen() and malloc() use size_t, while both read() and readv() use ssize_t.

So, ssize_t is not the signed version of size_t as there are values in ssize_t that cannot be mapped on a size_t (like -1) and viceversa. And library functions either use one type or the other one.

Then, to your questions, the two numbers you see differ by 5 units, that's exactly what you'd expect. What you see is the value of those two variables when seen as unsigned long. Try printing them as signed long (%ld) instead so you can still see the sign.

... why i got a wrong result also with ssize_t??

Use

ssize_t b = -30;
printf("%jd\n", (intmax_t) b); 

Use a matching specifier, which for a negative ssize_t is not %zu nor certainly "%zd".
How to use “zd” specifier with printf()?.

ssize_t b = -30;
printf("%zu\n", b);  // problem.

ssize_t does not have a C specified print specifier. C does not even specify ssize_t.

Various extensions to C do specify ssize_t and in a case of Linux, the print specifier also. Linux Programmer's Manual does have:

z: A following integer conversion corresponds to a size_t or ssize_t argument",

printf("%zd\n", b);  // OK for that Linux

POSIX B.2.12 Data Types has

ssize_t This is intended to be a signed analog of size_t. The wording is such that an implementation may either choose to use a longer type or simply to use the signed version of the type that underlies size_t.


Since ssize_t may (uncommonly) be wider than size_t, using "%zd" could invoke undefined behavior (UB). It is simple enough to cast to the widest standard signed type since C99 as intmax_t and print.

printf("%jd\n", (intmax_t) b);  // OK for general use

Overflow coz size_t is a UNSIGNED when you try to set size_t as (-val) you get overflow and get SIZE_T_MAX - val

for example: size_t val = -20; //val == 18446744073709551615 - 20;

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top