Разница между% u и% d в scanf ()

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

Ideone.com

Я вырыл глубже, чтобы найти, есть ли какая-либо разница. я нашел это

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 ++, верно? Если нет, меня интересуют оба.

-1

Решение

%d: Сканировать целое число как десятичное signed int, Аналогичный спецификатор преобразования, %i, интерпретирует число как шестнадцатеричное, когда ему предшествует 0x и восьмеричный, когда ему предшествует 0, В остальном он идентичен.

%u: Сканировать целое число как десятичное unsigned int,

8

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

Технически, вы вызываете неопределенное поведение при попытке прочитать отрицательное число в int с помощью %u спецификатор формата. Ты делаешь sscanf трактовать указатель на целое число со знаком как указатель на целое число без знака, и эти типы несовместимы. Это работает только потому, что как беззнаковые, так и знаковые целые имеют одинаковое представление битов, а целые числа со знаком используют представление с 2 дополнениями.

TL / DR: вы не гарантированно получите -2 от sscanf("-2", "%u", &u);

1

каждый спецификатор конверсии имеет соответствующий тип аргумента результата определено в спецификации 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).

0
По вопросам рекламы [email protected]