DourSquid
DourSquid

Reputation: 77

how to use scanf unsigned int

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

Answers (4)

Guy haimovitz
Guy haimovitz

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

Natesh Raina
Natesh Raina

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

pmg
pmg

Reputation: 108986

The C11 Standard states

"... 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

Peter
Peter

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

Related Questions