how to convert hex string to unsigned 64bit (uint64_t) integer in a fast and safe way?

24,025

Solution 1

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

Solution 2

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
}
Share:
24,025

Related videos on Youtube

Mickey Shine
Author by

Mickey Shine

Updated on July 18, 2020

Comments

  • Mickey Shine
    Mickey Shine almost 4 years

    I tried

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

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

    Thanks~

    • Mickey Shine
      Mickey Shine
      I don't know. I tried to use this to do the casting among a large number of hex strings, and sometimes it would report segment fault
    • DevSolar
      DevSolar
      Either your header or your source is wrong... (see intro of my answer)
    • DevSolar
      DevSolar
      See my answer. The "016" in combination with sscanf() doesn't make sense. Given that code snippet, strtol() or strtoll() (depending on platform) are the safer option. Check for success!
  • Flinsch
    Flinsch over 13 years
    Under my understanding, he wants to convert from integer to string, not vice versa. ;)
  • TOMKA
    TOMKA over 13 years
    @Flinsch, the title changed, but his original code suggests he wants to convert from string to integer. I'm not sure you can see the question's edit history, but the title originally stated that he wanted to convert a string to an integer.
  • DevSolar
    DevSolar over 13 years
    Actually, scanf() et al. are defined in terms of strtol(). For halfway decent input, they are functionally identical as far as parsing numbers is concerned. I admit strtol() handles failure more gracefully.
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE over 13 years
    Since accessing errno might be mildly expensive, I prefer only checking the value of errno if result was ULLONG_MAX. And EINVAL is optional on conversion failure, so for robustness you need to use the end-pointer argument and check whether it's equal to the starting pointer you passed in to know if any conversion was performed.
  • GreySage
    GreySage over 8 years
    Wouldn't strtoull() return an 'unsigned long long' type, which isn't necessarily a 'uint64_t' type?
  • autistic
    autistic almost 6 years
    This would be a good answer, but you shouldn't use scanf or sscanf to read signed integers because there's a risk of signed integer overflow... and that's a legitimate issue.
  • DevSolar
    DevSolar almost 6 years
    @autistic: So now you're looking through my profile to see if you can find other scanf-related answers of mine you can revenge-downvote? You're really making friends here. Note that there is no risk of signed integer overflow if you use scanf() on known-good input. As opposed to user input, which is what that other question (and comment) was about.
  • autistic
    autistic almost 6 years
    Actually, as I said, that is a legitimate issue... you said it yourself, in response to a question where it's barely relevant... in this question, on the other hand, you shouldn't even use a signed integer... the fact that you mentioned signed integers here makes this answer invalid.
  • DevSolar
    DevSolar almost 6 years
    @autistic: Note how the OP explicitly asserted that his int64 -- and thus mine as well -- is of type uint64_t, and thus unsigned.
  • autistic
    autistic almost 6 years
    What is the title of the question? "how to convert hex string to unsigned 64bit (uint64_t) integer in a fast and safe way?" So why do you say "your title suggested you'd want to write an int64" and "reading ... into an int64_t"?
  • autistic
    autistic almost 6 years
    I'm quoting your words, here... this is a problem... SCNx64 expects a uint64_t *, similar for PRIx64... That's a lowercase x, by the way. Another error to correct in this "would be good" answer.

Related