Question

I tried

sscanf(str, "%016llX", &int64 );

but seems not safe. Is there a fast and safe way to do the type casting?

Thanks~

Was it helpful?

Solution

Don't bother with functions in the scanf family. They're nearly impossible to use robustly. Here's a general safe use of strtoull:

char *str, *end;
unsigned long long result;
errno = 0;
result = strtoull(str, &end, 16);
if (result == 0 && end == str) {
    /* str was not a number */
} else if (result == ULLONG_MAX && errno) {
    /* the value of str does not fit in unsigned long long */
} else if (*end) {
    /* str began with a number but has junk left over at the end */
}

Note that strtoull accepts an optional 0x prefix on the string, as well as optional initial whitespace and a sign character (+ or -). If you want to reject these, you should perform a test before calling strtoull, for instance:

if (!isxdigit(str[0]) || (str[1] && !isxdigit(str[1])))

If you also wish to disallow overly long representations of numbers (leading zeros), you could check the following condition before calling strtoull:

if (str[0]=='0' && str[1])

One more thing to keep in mind is that "negative numbers" are not considered outside the range of conversion; instead, a prefix of - is treated the same as the unary negation operator in C applied to an unsigned value, so for example strtoull("-2", 0, 16) will return ULLONG_MAX-1 (without setting errno).

OTHER TIPS

Your title (at present) contradicts the code you provided. If you want to do what your title was originally (convert a string to an integer), then you can use this answer.


You could use the strtoull function, which unlike sscanf is a function specifically geared towards reading textual representations of numbers.

const char *test = "123456789abcdef0";

errno = 0;
unsigned long long result = strtoull(test, NULL, 16);

if (errno == EINVAL)
{
    // not a valid number
}
else if (errno == ERANGE)
{
    // does not fit in an unsigned long long
}

At the time I wrote this answer, your title suggested you'd want to write an uint64_t into a string, while your code did the opposite (reading a hex string into an uint64_t). I answered "both ways":

The <inttypes.h> header has conversion macros to handle the ..._t types safely:

#include <stdio.h>
#include <inttypes.h>

sprintf( str, "%016" PRIx64, uint64 );

Or (if that is indeed what you're trying to do), the other way round:

#include <stdio.h>
#include <inttypes.h>

sscanf( str, "%" SCNx64, &uint64 );

Note that you cannot enforce widths etc. with the scanf() function family. It parses what it gets, which can yield undesired results when the input does not adhere to expected formatting. Oh, and the scanf() function family only knows (lowercase) "x", not (uppercase) "X".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top