Scanf/Printf двойная переменная C
Скажем, у меня есть следующий бит кода в C:
double var;
scanf("%lf", &var);
printf("%lf", var);
printf("%f", var);
Он читает из переменной stdin 'var', а затем дважды печатает в stdout 'var'.
Я понимаю, что вы читаете двойную переменную из stdin, но мои вопросы:
- Почему вы можете печатать двойной с помощью% lf?
- Почему вы можете печатать двойной с% f?
- Какая из них лучше и правильнее использовать?
Ответы
Ответ 1
Для переменных аргументов, таких как printf
и scanf
, аргументы продвигаются, например, любые более мелкие целые типы повышаются до int
, float
продвигается до double
.
scanf
принимает параметры указателей, поэтому правило продвижения не действует. Он должен использовать %f
для float*
и %lf
для double*
.
printf
никогда не увидит аргумент float
, float
всегда продвигается до double
. Спецификатор формата %f
. Но C99 также говорит, что %lf
совпадает с %f
в printf
:
C99 §7.19.6.1 Функция fprintf
l
(ell) Указывает, что для аргумента long int
или unsigned long int
применяется следующий d
, i
, o
, u
, x
или x
; что следующий указатель преобразования n
применяется к указателю на аргумент long int
; что для аргумента wint_t
применяется следующий спецификатор преобразования c
; что следующий указатель преобразования s
применяется к указателю на аргумент wchar_t
; или не влияет на следующие a
, a
, e
, e
, f
, f
, g
или g
спецификатор преобразования.
Ответ 2
Насколько я читаю страницы руководства, scanf говорит, что модификатор длины l указывает (в случае плавающих точек), что аргумент имеет тип double, а не тип float, поэтому вы можете иметь lf, le, lg.
Что касается печати, официально в руководстве говорится, что "l" применяется только к целым типам. Поэтому он может не поддерживаться некоторыми системами или некоторыми стандартами. Например, при компиляции с gcc -Wall -Wextra -pedantic
появляется следующее сообщение об ошибке:
a.c:6:1: warning: ISO C90 does not support the ‘%lf’ gnu_printf format [-Wformat=]
Таким образом, вам может потребоваться удвоить, если ваш стандарт поддерживает синтаксис.
В заключение я бы сказал, что вы читаете "% lf", и вы печатаете с "% f".
Ответ 3
Когда a float
передается в printf
, он автоматически преобразуется в double
. Это часть рекламных акций по умолчанию, которые применяются к функциям, которые имеют список переменных параметров (содержащий ...
), в основном по историческим причинам. Поэтому "естественный" спецификатор для float
, %f
должен работать с аргументом double
. Поэтому спецификаторы %f
и %lf
для printf
одинаковы; они оба принимают значение double
.
Когда вызывается scanf
, указатели передаются, а не прямые значения. Указатель на float
не преобразуется в указатель на double
(это не сработало, поскольку объект с указателем не может измениться при изменении типа указателя). Итак, для scanf
аргумент для %f
должен быть указателем на float
, а аргумент для %lf
должен быть указателем на double
.