Почему scanf возвращает положительное значение, даже если входные данные больше, чем заданный числовой тип?

#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 даже при вводе типа like 123a .

2. «scanf может определить, что тип int слишком мал, чтобы содержать результат». -> Да, может, но функция не определена для этого. Теперь, если бы это было около 40 лет назад, все могло быть по-другому. (Помните, что тогда стоимость памяти может быть в 10 000 раз больше, чем сегодня)

3. Вам нужно написать свою собственную функцию преобразования

Ответ №1:

К сожалению, вы не можете полагаться на errno == ERANGE или подобное в переносимых программах на C.

fscanf не документировано авторитетно на cppreference.com , но в стандарте ISO C. Во-первых, стандарт гласит, что

  1. Функция 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 (и его братья и сестры) является переменной функцией. Есть смысл сообщить вызывающей стороне, сколько аргументов было успешно присвоено, где «успешно» может означать меньше, чем вы думаете. Ответственность за согласование аргументов лежит на вызывающей стороне.