I was trying to compare size_t
(long int
type for ubuntu) variable with int
constant 0
but turned out not working properly. but off_t
variable works fine.
size_t var = -3;
if(var < 0)
putchar('X');
else
putchar('Y');
// Y
but when I cast var
into int
, it works as I expect.
size_t var = -3;
if((int)var < 0)
putchar('X');
else
putchar('Y');
// X
but off_t
(long int
as well on my ubuntu) works fine without casting.
off_t var2 = -3;
if(var2 < 0)
putchar('X');
else
putchar('Y');
// X
Could you explain this please? Thanks.
CodePudding user response:
The type size_t
is an unsigned type. So when you attempt to assign the value -3 to it, the value gets converted into a very large positive value. This is why the condition in the first case is false.
In the second case, when casting var
to an int
, the assigned value (i.e. the very large positive value from before) is outside the range of int
so it gets converted in an implementation defined manner. On most implementations, this will result the value being converted to -3, so the condition will be true.
The type off_t
is a signed type so it is able to store the value -3, so the comparison works as expected.
CodePudding user response:
size_t
is an unsigned integer type, per C 2018 7.19 2. For illustration, in this answer I will treat it as 32 bits, with maximum value 4,294,967,295 (232−1), and I will treat int
as 32 bits, with minimum value −2,147,483,648 and maximum value 2,147,483,647. Widths of integer types can differ between C implementations.
For size_t var = -3;
, −3 is converted to the unsigned type. This conversion wraps modulo 4,294,967,296 (232), so 4,294,967,293 is stored in var
.
In var < 0
, the int
0
is converted to size_t
. This does not change the value; the result of the conversion is 0, just with type size_t
. Then the two size_t
values 4,294,967,293 and 0 are compared. Since 4,294,967,293 is not less than 0, the result of the comparison is false (zero).
In (int)var < 0
, the size_t
var
is converted to int
. Since 4,294,967,293 is greater than our int
can represent, the conversion is specified in C 2018 6.3.1.3 3, which says the result is implementation-defined. In common C implementations, it wraps modulo 232, in which case this conversion produces the value we started with −3. Then the int
values −3 and 0 are compared. Since −3 is less than 0, the result of the comparison is true (one).
off_t
is a signed integer type. (This is a Unix or other implementation-defined type, not a part of the C standard.) Since it is capable of representing −3, no change in value occurs when it is initialized with −3, and no change of value occurs when it is compared to 0
.