Почему scanf() нуждается в ”%lf" для удвоения, когда printf() подходит только для "%f”?
-
03-07-2019 - |
Вопрос
Почему это происходит scanf()
нуждается в l
в "%lf
" при чтении double
, когда printf()
можно использовать "%f
" независимо от того , является ли его аргумент double
или float
?
Пример кода:
double d;
scanf("%lf", &d);
printf("%f", d);
Решение
Потому что C преобразует значения float в double для функций, которые принимают переменные аргументы.Указатели ни на что не рекламируются, поэтому вы должны использовать %lf
, %lg
или %le
(или %la
в C99) для чтения в двойном формате.
Другие советы
Начиная с С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
в printf
для double
и продолжай %f
зарезервировано для float
аргументы.
scanf
необходимо знать размер данных, на которые указывает &d
чтобы заполнить его должным образом, в то время как вариационные функции увеличивают значения float до double (не совсем уверен, почему), так что printf
всегда получает double
.
Потому что в противном случае scanf подумает, что вы передаете указатель на значение с плавающей точкой, размер которого меньше, чем double , и вернет неверное значение.
Использование либо значения с плавающей запятой, либо двойного значения в выражении C приведет к получению значения, которое в любом случае является двойным, поэтому printf не сможет определить разницу.Принимая во внимание, что указатель на double должен быть явно передан scanf в отличие от указателя на float, потому что важно то, на что указывает указатель.