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);
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 thebase
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.
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 thebase
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With