Reputation: 77
I have the following
unsigned int value = 12;
int res = std::sscanf("-567", "%u", &value);
When this is run res is 1 indicating 1 match and value is set to 4294966729 Whereas I was expecting no matches to be made
I would be grateful if someone could explain this behaviour.
Upvotes: 5
Views: 37630
Reputation: 1625
This behavior happens because every negative integer has a corresponding unsigned value, allowing sscanf
to parse negative values for an unsigned int
. If you want to ensure that sscanf
matched a positive integer, you have to parse the string as decimal integer ("%d"
) and use an if
statement:
long int value:
unsigned int value_ui;
scanf("%ld", &value);
if (value < 0)
printf("error");
else
value_ui = (unsigned int) value;
Upvotes: 1
Reputation: 177
If you go through the docs of sscanf
function you will find that return type of sscanf
is the number of variables filled which is essentially one in this case i.e. the variable value
. Also value
is showing a very large number because you are storing a negative integer in it and displaying it in unsigned integer format. This will lead to modulo arithmetic and final result will be (-567)%(max unsigned integer value). To put it in simple words, it would be two's complement of 567. If instead you had used %d format specifier for value
it would have shown -567 only. For more details on sscanf
usage refer following link:
For C:http://www.tutorialspoint.com/c_standard_library/c_function_sscanf.htm
For C++:http://www.cplusplus.com/reference/cstdio/sscanf/
Upvotes: 0
Reputation: 108986
"... whose format is the same as expected for the subject sequence of the strtoul
function with the value 10 for the base argument ..."
and, for strtoul
"... If the subject sequence begins with a minus sign, the value resulting from the conversion is negated ..."
#include <stdio.h>
int main(void) {
unsigned int value;
int res;
res = sscanf("-567", "%u", &value);
if (res == 1) {
printf("Value: %u\n", value);
} else {
fprintf(stderr, "Error\n");
}
res = sscanf("567", "%u", &value);
if (res == 1) {
value = ~value + 1; // add 1 in two's complement machines
printf("Value: %u\n", value);
} else {
fprintf(stderr, "Error\n");
}
return 0;
}
Upvotes: 8
Reputation: 36617
Given your usage of std::sscanf()
, you're actually using C++, not C. But C++'s sscanf()
behaves in largely the same way as in C.
The specification of the %u
format specifier allows a sign to be included. Which would essentially mean modulo arithmetic will be employed. Assuming a 32 unsigned int
type, the result will be modulo 4294967296
to produce a value between 0
and 4294967295
. -567
modulo 4294967296
(aka the smallest positive remainder obtained on dividing -567
by 4294967296
) is 4294966729
.
Upvotes: 1