#include <stdio.h>
int main() {
float a = 1234.5f;
printf("%d\n", a);
return 0;
}
Он отображает 0
!! Как такое возможно? В чем причина?
Я намеренно поставил %d
в printf
утверждение, чтобы изучить поведение printf
.
Это потому, что %d
ожидает, int
но вы предоставили float.
Используйте %e
/ %f
/ %g
для печати поплавка.
Почему печатается 0: число с плавающей запятой преобразуется в double
перед отправкой в printf
. Число 1234,5 в двойном представлении с прямым порядком байтов:
00 00 00 00 00 4A 93 40
A %d
использует 32-битное целое число, поэтому печатается ноль. (В качестве теста вы могли printf("%d, %d\n", 1234.5f);
бы получить на выходе 0, 1083394560
.)
Что касается того, почему float
преобразован в double
, как прототип printf int printf(const char*, ...)
, из 6.5.2.2/7,
Обозначение с многоточием в деклараторе прототипа функции вызывает остановку преобразования типа аргумента после последнего объявленного параметра. По умолчанию продвижение аргументов выполняется для конечных аргументов.
и с 6.5.2.2/6,
Если выражение, обозначающее вызываемую функцию, имеет тип, который не включает прототип, целочисленные повышения выполняются для каждого аргумента, а аргументы, имеющие тип
float
, повышаются доdouble
. Они называются продвижением аргументов умолчанию .
(Спасибо Алоку за то, что узнал об этом.)
printf
это функция с переменным числом аргументов, а в стандарте сказано, что для функций с переменным числом аргументов a перед передачейfloat
преобразуется вdouble
.printf()
вызывает неопределенное поведение .Технически не говоря нет , каждая библиотека реализует свою собственную, и , следовательно, ваш метод пытается исследования «s поведение, делая то , что вы делаете, не будет много пользы. Вы могли бы попытаться изучить поведение в своей системе, и если да, вам следует прочитать документацию и посмотреть исходный код, чтобы узнать, доступен ли он для вашей библиотеки.
printf
printf
printf
printf
Например, на моем Macbook я получаю результат
1606416304
с вашей программой.Сказав это, когда вы передаете
float
переменную функцию,float
она передается какdouble
. Итак, ваша программа эквивалентна объявлению вa
виде файлаdouble
.Чтобы проверить байты a
double
, вы можете увидеть этот ответ на недавний вопрос здесь, на SO.Давайте сделаем это:
#include <stdio.h> int main(void) { double a = 1234.5f; unsigned char *p = (unsigned char *)&a; size_t i; printf("size of double: %zu, int: %zu\n", sizeof(double), sizeof(int)); for (i=0; i < sizeof a; ++i) printf("%02x ", p[i]); putchar('\n'); return 0; }
Когда я запускаю указанную выше программу, я получаю:
size of double: 8, int: 4 00 00 00 00 00 4a 93 40
Итак, первые четыре байта из числа
double
оказались равными 0, что может быть причиной того, что вы получили0
результат вашегоprintf
вызова.Для более интересных результатов мы можем немного изменить программу:
#include <stdio.h> int main(void) { double a = 1234.5f; int b = 42; printf("%d %d\n", a, b); return 0; }
Когда я запускаю указанную выше программу на своем Macbook, я получаю:
42 1606416384
С той же программой на машине Linux я получаю:
0 1083394560
источник
int
аргументы передаются в разных регистрах, чемdouble
аргументы.printf
with%d
принимаетint
аргумент, равный 42, а второй,%d
вероятно, печатает мусор, поскольку второгоint
аргумента не было.Спецификатор
%d
говоритprintf
ожидать целое число. Таким образом, первые четыре (или два, в зависимости от платформы) байта числа с плавающей запятой интерпретируются как целое число. Если они равны нулю, печатается ноль.Двоичное представление 1234.5 похоже на
1.00110100101 * 2^10 (exponent is decimal ...)
С компилятором C, который
float
фактически представляет собой двойные значения IEEE754, байты будут (если я не ошибся)01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000
В системе Intel (x86) с малым порядком байтов (т. Е. Первым идет младший байт), эта последовательность байтов меняется на обратную, так что первые четыре байта равны нулю. То есть то, что
printf
распечатывает ...См. Эту статью в Википедии о представлении с плавающей запятой в соответствии с IEEE754.
источник
Это из-за представления числа с плавающей запятой в двоичном формате. При преобразовании в целое число остается 0.
источник
Потому что вы вызвали неопределенное поведение: вы нарушили контракт метода printf (), солгав ему о типах его параметров, поэтому компилятор может делать все, что ему заблагорассудится. Это могло привести к выводу программы "dksjalk - тупица !!!" и технически это все равно было бы правильно.
источник
Причина в том, что
printf()
это довольно глупая функция. Он вообще не проверяет типы. Если вы говорите, что первый аргумент - этоint
(и это то, что вы говорите%d
), он верит вам и берет только байты, необходимые дляint
. В этом случае, если ваша машина использует четырехбайтовыеint
и восьмибайтовые байтыdouble
(float
преобразуется воdouble
внутреннююprintf()
), первые четыре байтаa
будут просто нулями, и это будет напечатано.источник
Он не будет автоматически преобразовывать float в целое число. Потому что оба имеют разный формат хранения. Поэтому, если вы хотите преобразовать, используйте приведение типов (int).
#include <stdio.h> int main() { float a = 1234.5f; printf("%d\n", (int)a); return 0; }
источник
Поскольку вы также пометили его с помощью C ++, этот код выполняет преобразование, как вы, вероятно, ожидаете:
#include <iostream.h> int main() { float a = 1234.5f; std::cout << a << " " << (int)a << "\n"; return 0; }
Выход:
1234.5 1234
источник
%d
десятичный%f
плаваетсм. больше здесь .
Вы получаете 0, потому что числа с плавающей запятой и целые числа представлены по-разному.
источник
Вам просто нужно использовать соответствующий описатель формата (% d,% f,% s и т. Д.) С соответствующим типом данных (int, float, string и т. Д.).
источник
Вы хотите% f, а не% d
источник
эй, он должен был что-то напечатать, поэтому он напечатал 0. Помните, что в C 0 все остальное!
источник
Это не целое число. Попробуйте использовать
%f
.источник