Почему функция scanf () нуждается в «% lf» для двойников, когда printf () в порядке с «% f»?

179

Почему это , что scanf()нуждается lв « %lf» при чтении double, когда printf()можно использовать « %f» независимо от того, является ли ее аргумент doubleили float?

Пример кода:

double d;
scanf("%lf", &d);
printf("%f", d);
Raldi
источник
1
Я не понимаю, что вы подразумеваете под указателем здесь. В scanf мы передаем только адрес & переменной (т.
7
@deetchanya В C, когда вы «берете адрес» переменной с унарным &оператором, результатом этой операции является указатель на место хранения переменной в памяти. Это тот указатель, который передается scanf.
zwol
это еще один пост, касающийся этого stackoverflow.com/questions/9291348/…
vimalpt

Ответы:

207

Потому что C будет продвигать числа с плавающей запятой для функций, которые принимают переменные аргументы. Указатели ни на что не повышаются, поэтому вы должны использовать %lf, %lgили %le(или %laв C99), чтобы читать в двойных.

MSN
источник
26

Начиная с С99 соответствие между спецификаторами формата и типами аргументов с плавающей запятой в C согласовано между printfи scanf. это

  • %f для float
  • %lf для double
  • %Lf для long double

Так уж получилось, что когда аргументы типа floatпередаются как переменные параметры, такие аргументы неявно преобразуются в тип double. Это причина, почему в printfспецификаторах формата %fи %lfэквивалентны и взаимозаменяемы. В printfвы можете "перекрестное использование" %lfс floatили %fс double.

Но на самом деле нет причин делать это на практике. Не используйте %fдля printfаргументов типа double. Это широко распространенная привычка, рожденная еще в C89 / 90 раз, но это плохая привычка. Используйте %lfв printffor doubleи оставьте %fзарезервированные для floatаргументов.

Муравей
источник
1
Я бы сказал, что использование %fв printf - хорошая привычка, потому что тогда ваш код всегда работает, тогда как использование %lfможет завершиться неудачей, если у компилятора нет библиотеки, совместимой с C99. К сожалению, такая ситуация действительно происходит.
ММ
Начиная с С99 соответствие между спецификаторами формата и типами аргументов с плавающей запятой в C согласовано между printfи scanf. Обратите внимание, что это не означает, что использование одного и того же спецификатора формата означает, что данные, записанные с помощью a, [f]printf()могут быть прочитаны [f]scanf(). Как правило, использование того же спецификатора формата, scanf()который использовался для printf(), не приведет к успешному чтению данных. Так , например, пространство обивка , которая может быть вставлена с помощью prinf()«S "%d"спецификатора формата будет пропущена к тому же "%d"спецификатору формата в scanf()вызове.
Эндрю Хенле
16

scanfЧтобы &dправильно заполнить данные, необходимо знать размер данных, на которые они указывают , тогда как функции с переменными числами повышают число с плавающей точкой до двойных (не совсем понятно, почему), поэтому printfвсегда получаем a double.

Tanktalus
источник
1
Функция variadic очень хрупкая, потому что она должна знать точный тип и размер всех параметров, передаваемых ей, и не может применять это во время компиляции. Если переменная неправильного типа, будет прочитано неправильное значение; если это неправильный размер, все переменные после будут также неправильно прочитаны. Если пропустить два разных размера поплавка, это вызовет всевозможные неприятные и легко пропускаемые проблемы.
mwfearnley
7

Потому что в противном случае scanf будет думать, что вы передаете указатель на число с плавающей точкой, размер которого меньше, чем double, и он вернет неправильное значение.

Джим Бак
источник
2

Использование значения с плавающей запятой или двойного значения в выражении C в любом случае приведет к двойному значению, поэтому printf не сможет определить разницу. Принимая во внимание, что указатель на двойник должен быть явно передан в scanf в отличие от указателя на число с плавающей точкой, потому что именно то, на что указывает указатель, имеет значение.

FCW
источник
5
float в этом случае конвертируется в double, поскольку аргументы являются частью списка аргументов переменной длины, float не всегда конвертируется в double в C.
Robert Gamble
1
В предстандартных версиях языка Си floatзначения автоматически переводились doubleв выражения. Это правило было отменено в стандарте C. Как правило, floatне применяется doubleв выражениях. Это только повышается, doubleкогда передается в качестве аргумента с переменным значением, что и происходит в этом случае.
AnT