Правильный спецификатор формата для double в printf


482

Каков правильный спецификатор формата doubleв printf? Это %fили это %lf? Я верю %f, но я не уверен.

Пример кода

#include <stdio.h>

int main()
{
   double d = 1.4;
   printf("%lf", d); // Is this wrong?
}

19
Если вы застряли с библиотекой C89, "%lf"не определено; в библиотеках C99 и C11 он определен так же, как "%f".
PMG

1
Ваш вариант настолько верен, насколько это возможно. %lfправильный формат формата для double. Но так стало в C99. До этого нужно было использовать %f.
AnT

Ответы:


626

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

Обратите внимание, что это единственное место, где printfстроки формата существенно отличаются от scanffscanfт. Д.) Строк формата. Для вывода, вы передаете значение , которое будет повышен с floatдо , doubleкогда передается в качестве параметра VARIADIC. Для ввода вы передаете указатель , который не продвигается, поэтому вы должны указать scanf, хотите ли вы прочитать a floatили a double, так как scanf, %fозначает, что вы хотите прочитать a, floatи %lfозначает, что вы хотите прочитать a double(и, для чего это стоит, для long double, вы используете %Lfдля либо printfили scanf).


1. C99, §6.5.2.2 / 6: «Если выражение, которое обозначает вызываемую функцию, имеет тип, который не включает в себя прототип, целочисленные преобразования выполняются для каждого аргумента, а аргументы, имеющие тип float, повышаются до двойного. Это называется продвижением аргументов по умолчанию. " В C ++ формулировка несколько иная (например, она не использует слово «прототип»), но эффект тот же: все переменные параметры проходят промоакции по умолчанию, прежде чем они будут получены функцией.


8
Обратите внимание, что g++отклоняет %lfпри компиляции с -Wall -Werror -pedantic:error: ISO C++ does not support the ‘%lf’ gnu_printf format
Kynan

2
@kynan: Если так (по крайней мере, если предположить текущую версию g ++), это ошибка в g ++. Для C89 / 90 и C ++ 98/03 разрешение lбыло расширением. Стандарты C99 / 11 и C ++ 11 требуют, чтобы реализация позволила это.
Джерри Гроб

1
Любопытно, что scanf делает покупку doubles лице %lf: она жалуется , что ожидалось float *и нашел double *только с %f.
Эрик Данд,

1
@JerryCoffin g ++ по умолчанию работает в режиме g ++ 98
ММ

5
@EricDand Это потому , что scanfпринимает указатели , где хранить то , что он читает, поэтому потребность знать , насколько большим являются пространство указываемым на это, в то время как printfпринимает сами значения, а «акцию аргументов по умолчанию» означает , как в конечном итоге , как doubleс, так что lэто по сути необязательно.
TripeHound

63

Учитывая стандарт C99 (а именно, черновик N1256 ), правила зависят от вида функции: fprintf (printf, sprintf, ...) или scanf.

Вот соответствующие извлеченные части:

предисловие

Настоящее второе издание отменяет и заменяет первое издание, ISO / IEC 9899: 1990, с поправками и исправлениями, изложенными в ISO / IEC 9899 / COR1: 1994, ISO / IEC 9899 / AMD1: 1995 и ISO / IEC 9899 / COR2: 1996. Основные изменения по сравнению с предыдущим изданием:

  • %lf спецификатор преобразования разрешен в printf

7.19.6.1 fprintfФункция

7 Модификаторы длины и их значения:

l (ell) Указывает, что (...) не влияет на следующий спецификатор преобразования a, A, e, E, f, F, g или G.

L Указывает, что следующий спецификатор преобразования a, A, e, E, f, F, g или G применяется к длинному двойному аргументу.

fprintfПрименяются те же правила printf, что sprintfи для похожих функций.

7.19.6.2 fscanfФункция

11 Модификаторы длины и их значения:

l (ell) Указывает, что (...) что следующий спецификатор преобразования a, A, e, E, f, F, g или G применяется к аргументу с указателем типа double;

L Указывает, что следующий аргумент преобразования a, A, e, E, f, F, g или G применяется к аргументу с указателем типа на long double.

12 Спецификаторы преобразования и их значения: a, e, f, g Соответствует необязательному знаку с плавающей запятой, (...)

14 Спецификаторы преобразования A, E, F, G и X также действительны и ведут себя так же, как, соответственно, a, e, f, g и x.

Короче говоря, для fprintfследующих спецификаторов и соответствующих типов указаны:

  • %f -> двойной
  • %Lf -> длинный двойной.

и для fscanfэтого есть:

  • %f -> плавать
  • %lf -> двойной
  • %Lf -> длинный двойной.

25

Это может быть %f, %gили в %eзависимости от того, как вы хотите, чтобы число было отформатировано. Смотрите здесь для более подробной информации. lМодификатор требуется scanfс double, но не в printf.


1
-1: l(нижний регистр) модификатор для целочисленных типов ( cplusplus.com/reference/clibrary/cstdio/printf ) и Lдля типов с плавающей запятой. Кроме того, Lмодификатор ожидает, а long doubleне простой double.
user470379

10
user470379: Так где же противоречие с моим ответом? Разве я не сказал, что lне требуется в printfтечение double.
Витаут

16

Формат %lf- это совершенно правильный printfформат double, именно так, как вы его использовали. Нет ничего плохого в вашем коде.

Формат %lfin printfне поддерживался в старых (до C99) версиях языка C, что создавало поверхностную «несогласованность» между спецификаторами формата для doublein printfи scanf. Это поверхностное несоответствие было исправлено в C99.

Вы не обязаны использовать %lfс doubleв printf. Вы также можете использовать %f, если вы так предпочитаете ( %lfи %fэквивалентны в printf). Но в современном C имеет смысл предпочесть использовать %fс float, %lfс doubleи %Lfс long double, последовательно в обоих printfи scanf.


С scanf(), "%f", "%lf"Совпадение float *, double *, не float, doubleкак следует из последней строки.
chux - Восстановить Монику

9

%Lf(обратите внимание на заглавную L) это спецификатор формата для длинных двойников .

Для равнины doubles, либо %e, %E, %f, %gили %Gбудут делать.


Какая разница между %gа %G?
Янп

@yanpas, нижний / верхний регистр для символа степени, соответственно.
Фредерик Хамиди

извините,% g и% G выводят символ E Также они выводят INF и Inf в разных случаях
янп
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.