Как работает эта программа?

#include <stdio.h>

int main() {
    float a = 1234.5f;
    printf("%d\n", a);
    return 0;
}

Он отображает 0!! Как это возможно? Что такое рассуждение?


Я намеренно положил %d в оператор printf для изучения поведения printf.

Ответ 1

Это потому, что %d ожидает int, но вы предоставили поплавок.

Используйте %e/%f/%g для печати поплавка.


В чем причина печати 0: номер с плавающей запятой преобразуется в double перед отправкой на printf. Число 1234,5 в двойном представлении в маленьком значении endian

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. Они называются рекламными акциями по умолчанию.

(Спасибо Алоку за это.)

Ответ 2

Технически говоря, нет 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

Ответ 3

Спецификатор %d сообщает printf ожидать целое число. Таким образом, первые четыре (или два, в зависимости от платформы) байта float intepreted как целое число. Если они оказываются нулевыми, то печатается нуль

Двоичное представление 1234.5 похоже на

1.00110100101 * 2^10 (exponent is decimal ...)

С компилятором C, который представляет float в действительности как двойные значения IEEE754, байты будут (если бы я не ошибся)

01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000

В системе Intel (x86) с небольшим энтиссасом (то есть наименее значимым байтом, который появляется первым) эта последовательность байтов меняется на обратную, так что первые четыре байта равны нулю. То есть, что printf печатает...

См. Эта статья в Википедии для представления с плавающей точкой в ​​соответствии с IEEE754.

Ответ 4

Поскольку вы вызывали поведение undefined: вы нарушили контракт метода printf(), опираясь на него о его типах параметров, поэтому компилятор может делать все, что угодно. Это может сделать выход программы "dksjalk - это ninnyhead!!!" и технически это все равно будет правильным.

Ответ 5

Это из-за представления float в двоичном формате. Преобразование в целое число оставляет его с 0.

Ответ 6

Причина в том, что printf() - довольно глупая функция. Он не проверяет типы вообще. Если вы скажете, что первым аргументом является int (и это то, что вы говорите с помощью %d), он считает, что вы и берете только байты, необходимые для int. В этом случае, если ваш компьютер использует четырехбайтовые int и восьмибайтовые double (float преобразуется в double внутри printf()), первые четыре байта a будут просто нулей, и это печатается.

Ответ 7

Он не будет автоматически конвертировать float в integer. Потому что оба имеют другой формат хранения. Поэтому, если вы хотите преобразовать, используйте (int) typecasting.

#include <stdio.h>

int main() {
    float a = 1234.5f;
    printf("%d\n", (int)a);
    return 0;
}

Ответ 8

Поскольку вы также отметили его с помощью С++, этот код делает преобразование, как вы, вероятно, ожидаете:

#include <iostream.h>

int main() {
    float a = 1234.5f;
    std::cout << a << " " << (int)a << "\n";
    return 0;
}

Вывод:

1234.5 1234

Ответ 9

%d является десятичным

%f - float

см. больше этих здесь.

Вы получаете 0, потому что поплавки и целые числа представлены по-разному.

Ответ 10

Вам просто нужно использовать соответствующий спецификатор формата (% d,% f,% s и т.д.) с соответствующим типом данных (int, float, string и т.д.).

Ответ 11

Это не целое число. Попробуйте использовать %f.

Ответ 12

Вы хотите% f не% d

Ответ 13

Эй, он должен был напечатать что-то, чтобы напечатать 0. Помните, что в C 0 все остальное!