sscanf and %i / radix detection of large unsigned integers

Viewed 132

I'm working with files containing large numbers (disk offsets) and have run into a problem using scanf for %lli - the numbers are of the format 0x... but scanf doesn't read all the bits.

Here's example code (I tested on https://www.onlinegdb.com/online_c_compiler).

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char* str = malloc(30);
    unsigned long long l;
    sprintf(str, "0x%llx\n", 0xffffffffffffffffULL);
    printf("%s\n", str);
    sscanf(str, "%lli", &l);
    printf("%llx\n", l);

    return 0;
}

It outputs:

0xffffffffffffffff

7fffffffffffffff

whereas I expect both numbers to be equal.

If I use the %llx specifier, it works properly, but I don't want to limit myself to hex-formatted numbers.

2 Answers

Unfortunately i stands for signed integer, and the corresponding expected argument is a pointer to int; with ll the width will be long long, but it would still be signed. There is no scanf format character for unsigned integer with base detection.


There is no perfect solution. You can use strtoull(str, &endptr, 0) (or even strtoumax), which will detect the format correctly, but it is much more tedious to use.

But scanf is not perfect either - if the number is too big, then you would always get the maximum value, just like you got LLONG_MAX, without error indication.

%lli is for long long signed int (which only goes up to 0x7fffffffffffffff on your system).

%llu is for long long unsigned int (which is what you are trying to read).

Replace the former for the latter.

Related