В C ++, если я читаю целое число из строки, кажется, что не имеет значения, использую ли я u
или же d
как спецификатор преобразования, поскольку оба принимают даже отрицательные целые числа.
#include <cstdio>
using namespace std;
int main() {
int u, d;
sscanf("-2", "%u", &u);
sscanf("-2", "%d", &d);
puts(u == d ? "u == d" : "u != d");
printf("u: %u %d\n", u, u);
printf("d: %u %d\n", d, d);
return 0;
}
Я вырыл глубже, чтобы найти, есть ли какая-либо разница. я нашел это
int u, d;
sscanf("-2", "%u", &u);
sscanf("-2", "%d", &d);
эквивалентно
int u, d;
u = strtoul("-2", NULL, 10);
d = strtol("-2", NULL, 10);
в соответствии с cppreference.com.
Есть ли разница между u
а также d
при использовании этих спецификаторов преобразования для разбора, т.е. в формате, переданном в scanf
функции типа? Что это?
Ответ одинаков для C и C ++, верно? Если нет, меня интересуют оба.
%d
: Сканировать целое число как десятичное signed int
, Аналогичный спецификатор преобразования, %i
, интерпретирует число как шестнадцатеричное, когда ему предшествует 0x
и восьмеричный, когда ему предшествует 0
, В остальном он идентичен.
%u
: Сканировать целое число как десятичное unsigned int
,
Технически, вы вызываете неопределенное поведение при попытке прочитать отрицательное число в int
с помощью %u
спецификатор формата. Ты делаешь sscanf
трактовать указатель на целое число со знаком как указатель на целое число без знака, и эти типы несовместимы. Это работает только потому, что как беззнаковые, так и знаковые целые имеют одинаковое представление битов, а целые числа со знаком используют представление с 2 дополнениями.
TL / DR: вы не гарантированно получите -2 от sscanf("-2", "%u", &u);
каждый спецификатор конверсии имеет соответствующий тип аргумента результата определено в спецификации C. %u
а также %d
директивы преобразования действительно принять те же входы, как вы заметили, но аргумент, соответствующий %u
должен быть типа unsigned int*
не int*
, То есть Ваш пример должен быть исправлен как:
unsigned int u;
int d;
sscanf("-2", "%u", &u);
sscanf("-2", "%d", &d);
Если бы вы включили предупреждения, вы получите их при компиляции исходного примера. А также по праву:
Если подавление присваивания не было указано *, результат преобразования помещается в объект, на который указывает первый аргумент, следующий за аргументом формата, который еще не получил результат преобразования. Если этот объект не имеет подходящего типа, или если результат преобразования не может быть представлен в объекте, поведение не определено.
Акцент мой.
Итак, вы призывали неопределенное поведение (см часть Что такое неопределенное поведение). Когда вы вызываете неопределенное поведение, вы одиноки, и могут произойти неприятные вещи.
Модификаторы конверсии определены в C99 (последний публичный проект, N1256; официальный PDF). Определение такое же, как в C11 (последний публичный проект, N1570; официальный PDF). самый последний проект C ++ (по состоянию на 2015-02-10, N4567) связаны с список стандартных документов C ++ под другим вопросом о переполнении стека принимает определение cstdio
заголовок от C99 а также не изменяет это (Помимо поместив функции в std
Пространство имен и незначительные изменения, упомянутые в § 27.9.2).