Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a negative number converted to size_t become a huge number in C?

Tags:

c

unsigned

size-t

When I build a simple program that lets the user enter a number (size_t num), I don't understand why input of a negative number results in a huge number instead of an error message.

size_t num;
printf("enter num:");
scanf("%lu",&num);
printf("%lu",num);
like image 232
ron Avatar asked Mar 02 '23 14:03

ron


2 Answers

The %u format specifier will actually accept a string representation of a signed integer, with the result being converted to an unsigned integer.

Section 7.21.6.2p12 of the C standard regarding the fscanf function (and by extension, scanf) says the following about the u conversion specifier:

Matches an optionally signed decimal integer, whose format is the same as expected for the subject sequence of the strtoul function with the value 10 for the base argument. The corresponding argument shall be a pointer to unsigned integer.

The conversion from signed to unsigned happens by logically adding the maximum value the unsigned type can hold +1 to the numeric value of the signed type until the result is in the range of the unsigned type. Note that this happen regardless of the underlying representation of the relevant integer types.

So for example, assuming size_t is a 64 bit type, the largest value it can hold is 18446744073709551615. So if you input -1 then 18446744073709551616 is added to -1 to give you 18446744073709551615 which is the result.

This conversion is documented in section 6.3.1.3:

1 When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.

2 Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

3 Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

like image 68
dbush Avatar answered Mar 29 '23 23:03

dbush


The specification for the u conversion in C 2018 7.21.6.2 12 says:

Matches an optionally signed decimal integer, whose format is the same as expected for the subject sequence of the strtoul function with the value 10 for the base argument. The corresponding argument shall be a pointer to unsigned integer.

(The l modifier further qualifies it to be an unsigned long.)

Thus, a sign is permitted when scanning with %lu. Per paragraph 10:

… the input item … is converted to a type appropriate to the conversion specifier.

Conversions to unsigned long wrap modulo ULONG_MAX+1, so small negative values are converted to large positive values.

Incidentally, to scan a numeral into a size_t, you should use %zu. The z modifier is specifically for size_t.

like image 30
Eric Postpischil Avatar answered Mar 29 '23 22:03

Eric Postpischil