sscanf - чтение шестнадцатеричных значений не будет работать с запятой

Я пытаюсь пропустить строку и проанализировать два значения, как в коде ниже:

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;
}

Он возвращает следующий вывод:

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

Неверное шестнадцатеричное значение. Когда , в format[] удаляется, вывод выглядит следующим образом:

Status: 1, HEX_DATA: d800, NEGATIVE_VAL: 0

Теперь значение hex_data анализируется правильно, но neg_val не анализируется. Как разобрать их все?


person Tyrreus    schedule 25.03.2020    source источник


Ответы (2)


Вместо использования %*s вам следует использовать %*[^,],, чтобы игнорировать все символы (включая пробелы) до первой запятой перед HEX_DATA включительно.

Кроме того, %04x для записи требуется (un)signed int, а не uint16_t (также не требуется начальный 0). И %d для записи нужен (signed) int, а не int8_t. Используйте модификаторы типа h и hh для записи в меньшие типы соответственно.

Дополнительные сведения см. в этой ссылке.

Попробуйте это вместо этого:

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;
}

Выход:

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

Живое демо

ОБНОВЛЕНИЕ. Или лучше используйте вспомогательные макросы формата SCNd8, SCNx16, PRId8 и PRIx16 из <inttypes.h>, например:

#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;
}

Выход:

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

Текущая демонстрация

person Remy Lebeau    schedule 25.03.2020
comment
Запятая — это селедка, она не имеет ничего общего с проблемой. Вы можете изменить спецификацию scanf, чтобы использовать %*[^,] вместо %*s, но на самом деле это не имеет ничего общего с вопросом или проблемой. - person Chris Dodd; 26.03.2020
comment
@ChrisDodd Запятая - это ерунда - это зависит от того, содержит ли text_to_be_skipped пробел или нет. Очевидно, что в приведенном примере это не так, но мы явно не знаем реального содержания text_to_be_skipped в производственном коде OP. %*s прекратит синтаксический анализ, если встретит пробел перед запятой (ideone.com/g8pCvo), тогда как %*[^,], остановит синтаксический анализ только если встречается запятая (ideone.com/iTtw98). И поскольку перед HEX_DATA явно стоит запятая, я бы выбрал последнее, чтобы быть в безопасности. - person Remy Lebeau; 26.03.2020
comment
Я бы сказал, что он может содержать запятую (или не заканчиваться запятой) с такой же вероятностью, как и пробел - что-либо более сложное, чем пример, может быть проблемой, и на самом деле не имеет ничего общего с проблемой возврата sscanf очевидный успех (2) с неверными данными в переменных. - person Chris Dodd; 26.03.2020

Проблема в том, что ваши типы данных не соответствуют вашей строке формата — x предназначен для чтения беззнакового целого, а не uint16_t, а d — для int, а не int8_t. Пытаться

char format[] = "%*s HEX_DATA:%04"SCNx16", NEGATIVE_VAL:%"SCNd8;
person Chris Dodd    schedule 25.03.2020
comment
Также измените %04 на %4, 0 бесполезен и сбивает с толку. - person chqrlie; 26.03.2020
comment
@chqrlieforyellowblockquotes: правда, это не имеет никакого эффекта, но это не вредно -- это не имеет никакого эффекта - person Chris Dodd; 26.03.2020