sscanf(s, "%u", &v) соответствует целым числам со знаком

После того, как Cppcheck жаловался на "%u" как неправильный спецификатор формата для сканирования в int переменная, я изменил формат в "%d", но когда я посмотрел на него еще раз, прежде чем вносить изменения, я подумал, что намерение может состоять в том, чтобы предотвратить негативные воздействия. Я написал две небольшие программы, чтобы увидеть разницу:

Спецификатор%d

#include <iostream>
#include <stdlib.h>
using namespace std;

int main() {
    const char* s = "-4";
    int value = -1;
    int res = sscanf(s, "%d", &value);
    cout << "value:" << value << endl;
    cout << "res:" << res << endl;
    return 0;
}

см. также https://ideone.com/OR3IKN

Спецификатор%u

#include <iostream>
#include <stdlib.h>
using namespace std;

int main() {
    const char* s = "-4";
    int value = -1;
    int res = sscanf(s, "%u", &value);
    cout << "value:" << value << endl;
    cout << "res:" << res << endl;
    return 0;
}

см. также https://ideone.com/WPWdqi

Результаты)

Удивительно, но оба спецификатора преобразования принимают знак:

value:-4
res:1

Я заглянул в документацию на cppreference.com. Для C ( scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s - cppreference.com), а также C++ ( std:: scanf, std:: fscanf, std:: sscanf - cppreference.com) описание для "%u" спецификатор конверсии тот же (выделено мной):

соответствует беззнаковому десятичному целому числу
Формат числа совпадает с ожидаемым strtoul() со значением 10 для базового аргумента.

Соответствует ли стандарт наблюдаемого поведения? Где я могу найти это документально?

[Обновление] Неопределенное поведение, действительно, почему?

Я читал, что это был просто UB, ну, чтобы добавить к путанице, вот версия, объявляющая значение как unsigned https://ideone.com/nNBkqN - я думаю, что назначение -1 по-прежнему, как и ожидалось, но "%u", очевидно, все еще соответствует знаку:

#include <iostream>
#include <stdlib.h>

using namespace std;

int main() {
    const char* s = "-4";
    unsigned value = -1;
    cout << "value before:" << value << endl;
    int res = sscanf(s, "%u", &value);
    cout << "value after:" << value << endl;
    cout << "res:" << res << endl;
    return 0;
}

Результат:

value before:4294967295
value after:4294967292
res:1

2 ответа

Решение

Есть два отдельных вопроса.

  1. %u ожидает unsigned int* аргумент; прохождение int* это UB.
  2. Есть ли %u матч -4? Да. Ожидаемый формат strtoul с основанием 10, и если вы читаете документацию, совершенно ясно, что разрешен начальный знак минус.

Нет, это не соответствует стандарту. На самом деле поведение вашей программы не определено: спецификатор формата для sscanf должен соответствовать типам аргументов.

Другие вопросы по тегам