Код формата %f
printf указан как работающий со значением типа double
[ source ].Однако простая тестовая программа демонстрирует, что она также может использоваться со значениями типа float
.Как это работает?
Эквивалентный случай с целочисленными типами (например, int
и long long int
) "работает", потому что на машинах с прямым порядком байтов младшие байты 32-битного целого числа случаются сперекрывают младшие байты 64-разрядного целого числа, поэтому, если верхние биты равны 0, вы получите «правильный» ответ.
Но это не может быть в случае float
и double
, потому что форматы с плавающей запятой не являются взаимозаменяемыми, как это.Вы просто не можете напечатать значение с плавающей запятой как двойное без выполнения (довольно сложного) преобразования в другой формат.Попытка сделать это с помощью ввода типов будет просто выводить мусор.
Кроме того, printf
является вариативным.Компилятор не обязательно знает во время компиляции, какие спецификаторы формата будут использоваться, только типы аргументов.Поэтому единственное, что я могу предположить, это то, что все float
значения, передаваемые в функцию с переменным числом, будут безоговорочно обновлены до double
.Но меня поражает, что я мог так долго программировать на C и не знать об этом.
Как C делает здесь неявное принуждение?
Источник:
#include <stdio.h>
#include <math.h>
int main() {
float x[2] = {M_PI, 0.0};
printf("value of x: %.16e\n", x[0]);
printf("size of x: %lu\n", sizeof(x[0]));
double *xp = (double *)&x[0];
printf("value of *xp: %.16e\n", *xp);
printf("size of *xp: %lu\n", sizeof(*xp));
double y = M_PI;
printf("value of y: %.16e\n", y);
printf("size of y: %lu\n", sizeof(y));
int i[2] = {1234, 0};
printf("value of i: %lld\n", i[0]);
printf("sizeof of i: %lu\n", sizeof(i[0]));
long long *ip = (long long *)&i[0];
printf("value of i: %lld\n", *ip);
printf("sizeof of i: %lu\n", sizeof(*ip));
return 0;
}
Вывод:
value of x: 3.1415927410125732e+00
size of x: 4
value of *xp: 5.3286462644388174e-315
size of *xp: 8
value of y: 3.1415926535897931e+00
size of y: 8
value of i: 1234
sizeof of i: 4
value of i: 1234
sizeof of i: 8
Команда и версия компиляции:
$ gcc test_float.c -o test_float
$ gcc --version
gcc (Ubuntu 5.5.0-12ubuntu1~16.04) 5.5.0 20171010
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.