sscanf (s, «% u», & amp; 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

4

Решение

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

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

Другие решения

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

3