#c
#c
Вопрос:
Учитывая следующий код :
int x;
int r = scanf("%d", amp;x);
почему scanf возвращается 1
, когда пользователь вводит число, большее INT_MAX
или даже большее, чем LONG_MAX
?
Из документации:
Number of receiving arguments successfully assigned.
Почему x
считается успешно назначенным? Что это означает именно в этом контексте? Когда пользователь вводит числа между INT_MAX
и LONG_MAX
, x
появляется нижняя половина результата. Я знаю scanf
, что использует strtol
внутренне, но scanf
могу определить, что тип int
слишком мал, чтобы содержать результат. Кроме того, при передаче гигантского числа, большего, чем LONG_MAX
, значение x
равно -1
, а возвращаемое значение равно 1
, и я должен полагаться на errno
проверку, что что-то пошло не так ( errno == ERANGE
) .
Что означает «успешно назначенный» и почему scanf
возвращает 1
, учитывая, что он может так легко сказать, что результат на самом деле является мусором?
Комментарии:
1. Обратите внимание, что
scanf
это вернет 1 даже при вводе типа like123a
.2. «scanf может определить, что тип int слишком мал, чтобы содержать результат». -> Да, может, но функция не определена для этого. Теперь, если бы это было около 40 лет назад, все могло быть по-другому. (Помните, что тогда стоимость памяти может быть в 10 000 раз больше, чем сегодня)
3. Вам нужно написать свою собственную функцию преобразования
Ответ №1:
К сожалению, вы не можете полагаться на errno == ERANGE
или подобное в переносимых программах на C.
fscanf
не документировано авторитетно на cppreference.com , но в стандарте ISO C. Во-первых, стандарт гласит, что
- Функция fscanf возвращает значение макроса
EOF
, если сбой ввода происходит до завершения первого преобразования (если таковое имеется). В противном случае функция возвращает количество назначенных входных элементов, которое может быть меньше, чем предусмотрено, или даже равно нулю, в случае раннего сбоя сопоставления.
Т.е. нигде не содержится слово «успешный».
Напротив, он говорит:
[…] если результат преобразования не может быть представлен в объекте, поведение не определено.
Т.е., к сожалению, в этом случае нет никаких гарантий поведения. В частности, в стандарте никогда не указано, что результатом будет наибольшее число, или которое errno
будет содержать ERANGE
или любую другую подобную вещь.
Ответ №2:
почему scanf возвращает 1, когда пользователь вводит число, большее, чем INT_MAX или даже больше, чем LONG_MAX ?
Это неопределенное поведение (UB), когда входной текст преобразуется в значение вне int
диапазона for "%d"
. Это недостаток спецификации scanf()
.
Может случиться все, что угодно.
Надежный код отделяет ввод от преобразования. Посмотрите на fgets()
и strtol()
.
Ответ №3:
«scanf» — это функция, которая считывает данные с указанным форматом из заданного источника потока строк. Это позволяет программисту принимать входные данные от стандартного устройства ввода (клавиатуры) и сохраняет их в переменных.
«scanf» означает «формат сканирования», потому что он сканирует входные данные на наличие допустимых токенов и анализирует их в соответствии с указанным форматом.
Считывает действительное число, которое (по умолчанию) пользователь ввел в переменную miles
- Каждой переменной должен предшествовать оператор адреса амперсанда (amp;).
- Мы можем считывать значения в несколько переменных с помощью одного scanf, если у нас есть соответствующие строки формата для каждой переменной.
«scanf» успешно выполняет функцию «формат сканирования». В функции «scanf» не входит проверка диапазона для соответствующего типа данных.
Ответ №4:
Помните, что scanf (и его братья и сестры) является переменной функцией. Есть смысл сообщить вызывающей стороне, сколько аргументов было успешно присвоено, где «успешно» может означать меньше, чем вы думаете. Ответственность за согласование аргументов лежит на вызывающей стороне.