1
#include <cstdio>
#include <cstdint>
#include <cassert>

int main() {
    std::uint64_t ui;
    char c;
    auto ret = std::sscanf("111K", "%lu64%[B, K, M, G]", &ui, &c);

    assert(ret == 2);
    assert(ui == 111);
}

I tried to use sscanf to read a uint64_t and a char from one string, but it only read it ui (assertion ret == 2 fails) every time I tried this.

JiaHao Xu
  • 1,556
  • 8
  • 21

3 Answers3

4

You have two issues here. First

%lu64

should be

"%" SCNu64 

to read in a 64 bit integer.

The second issue is

%[B, K, M, G]

requires a char* or wchar_t* as its output parameter as it populates a c-string. You need to change

char c;

to at least

char c[2] // 2 because it adds a null terminator

in order capture K. We put that all together and we get

auto ret = std::sscanf("111K", "%" SCNu64 "%[B, K, M, G]", &ui, c);

Do note that

%[B, K, M, G]

is actually trying to match all of the spaces and comma inside the brackets. You could also write it as

%[BKMG]

and get the same results.

NathanOliver
  • 150,499
  • 26
  • 240
  • 331
3

Your format string expects characters 64 to follow the integer. %lu is the format specifier; 64 are literal characters.

Igor Tandetnik
  • 45,980
  • 4
  • 51
  • 75
3

Your format string is invalid. It should go like this on 64 bit builds: "%lu%1[BKMG]" and "%llu%1[BKMG]" when building for 32 bits.

The universal solution uses SCNu64 macro: "%" SCNu64 "%1[BKMG]". This macro is defined in cinttypes header file.

Also your last parameter is passed incorrectly. It have to be an array of characters since zero will be appended at the end. Your code leads to undefined behavior since when c value will be written, something beyond this variable also will be written.

#include <cstdio>
#include <cstdint>
#include <cassert>
#include <iostream>

int main() {
    std::uint64_t ui;
    char s[32];
    auto ret = std::sscanf("111K", "%lu%1[BKMG]", &ui, s);

    std::cout << "ret=" << ret << "  ui=" << ui << " s=" << s << "\n";

    return 0;
}

https://wandbox.org/permlink/17vZ8OkydJ7zQmP4
https://wandbox.org/permlink/z21Rbsu4mAseZyS4

Marek R
  • 23,155
  • 5
  • 37
  • 107
  • It's just interesting that in case of `char s[1]` (or using a single `char` instead as in the question), `sscanf` might rewrite the lsb of `ui` with trailing zero on the stack. Which then silently results in `ui` having zero value. Of course, this is undefined behavior. – Daniel Langr Nov 02 '18 at 14:08
  • this is undefined behavior, so anything can happen. – Marek R Nov 02 '18 at 14:09
  • Sure, this is what I wrote. Someone just might wonder that it can result in `c` having value `'K'` and `ui` having value 0 instead of 111. – Daniel Langr Nov 02 '18 at 14:11