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
??
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
.
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
orssize_t
argument",
printf("%zd\n", b); // OK for that Linux
ssize_t
This is intended to be a signed analog ofsize_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 underliessize_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;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.