sscanf - read hex values won't work with comma

Viewed 194

I'm trying to skip string and parse two values as in code below:

int main()
{
    char format[] = "%*s HEX_DATA:%04x, NEGATIVE_VAL:%d";
    char str[] = "text_to_be_skipped, HEX_DATA:d800, NEGATIVE_VAL:-20";

    uint16_t hex_data = 0;
    int8_t neg_val = 0;

    int status = sscanf(str, format, &hex_data, &neg_val);

    printf("Status: %d, HEX_DATA: %04x, NEGATIVE_VAL: %d", status, hex_data, neg_val);

    return 0;
}

It returns the following output:

Status: 2, HEX_DATA: ffff, NEGATIVE_VAL: -20

The hex value is wrong. When , in format[] is removed then output is as follows:

Status: 1, HEX_DATA: d800, NEGATIVE_VAL: 0

Now hex_data value is parsed correctly but neg_val is not parsed. How to parse them all?

2 Answers

Rather than using %*s, you should instead use %*[^,], to ignore all characters (including whitespace) up to, and including, the first comma before HEX_DATA.

Also, %04x needs an (un)signed int to write to, not a uint16_t (also, the leading 0 is not needed). And %d needs a (signed) int to write to, not a int8_t. Use the h and hh type modifiers to write to smaller types, respectively.

See this reference for more details.

Try this instead:

int main()
{
    char format[] = "%*[^,], HEX_DATA:%4hx, NEGATIVE_VAL:%hhd";
    char str[] = "text_to_be_skipped, HEX_DATA:d800, NEGATIVE_VAL:-20";

    uint16_t hex_data = 0;
    int8_t neg_val = 0;

    int status = sscanf(str, format, &hex_data, &neg_val);

    printf("Status: %d, HEX_DATA: %04x, NEGATIVE_VAL: %d", status, hex_data, neg_val);

    return 0;
}

Output:

Status: 2, HEX_DATA: d800, NEGATIVE_VAL: -20

Live Demo

UPDATE: Or better, use the SCNd8, SCNx16, PRId8, and PRIx16 format helper macros from <inttypes.h>, eg:

#include <inttypes.h>

int main()
{
    char format[] = "%*[^,], HEX_DATA:%4" SCNx16 ", NEGATIVE_VAL:%" SCNd8;
    char str[] = "text_to_be_skipped, HEX_DATA:d800, NEGATIVE_VAL:-20";

    uint16_t hex_data = 0;
    int8_t neg_val = 0;

    int status = sscanf(str, format, &hex_data, &neg_val);

    printf("Status: %d, HEX_DATA: %04" PRIx16 ", NEGATIVE_VAL: %" PRId8, status, hex_data, neg_val);

    return 0;
}

Output:

Status: 2, HEX_DATA: d800, NEGATIVE_VAL: -20

Live Demo

The problem is that your data types don't match your format string -- x is for reading an unsigned int, not a uint16_t, and d is for an int, not an int8_t. Try

char format[] = "%*s HEX_DATA:%04"SCNx16", NEGATIVE_VAL:%"SCNd8;
Related