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

#include <stdio.h>

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

Он отображает 0 !! Как это возможно? В чем причина?


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

88
задан claws 11 April 2012 в 03:49
поделиться

13 ответов

Это потому, что % d ожидает int , но вы указали число с плавающей запятой.

Используйте % 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 . Это называется продвижением аргументов по умолчанию .

(Спасибо, Алок, за то, что это выяснил.)

238
ответ дан 24 November 2019 в 07:23
поделиться

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

0
ответ дан 24 November 2019 в 07:23
поделиться

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

0
ответ дан 24 November 2019 в 07:23
поделиться

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

#include <iostream.h>

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

Вывод:

1234.5 1234
2
ответ дан 24 November 2019 в 07:23
поделиться

С технической точки зрения не существует the printf , каждая библиотека реализует свою собственную, и, следовательно, ваш метод изучения поведения printf , выполняя то же самое, что и вы. не принесет особой пользы. Вы могли бы попытаться изучить поведение printf в вашей системе, и если да, вам следует прочитать документацию и посмотреть исходный код для printf , если он доступен для вашей библиотека.

Например, на моем Macbook я получаю результат 1606416304 с вашей программой.

Сказав это, когда вы передаете float вариативной функции, float передается как double . Итак, ваша программа эквивалентна объявлению a как double .

Чтобы проверить байты 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
45
ответ дан 24 November 2019 в 07:23
поделиться

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

#include <stdio.h>

int main() {
    float a = 1234.5f;
    printf("%d\n", (int)a);
    return 0;
}
3
ответ дан 24 November 2019 в 07:23
поделиться

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

0
ответ дан 24 November 2019 в 07:23
поделиться

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

1
ответ дан 24 November 2019 в 07:23
поделиться

% d десятичное

% f плавающее

подробнее см. здесь .

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

1
ответ дан 24 November 2019 в 07:23
поделиться

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

5
ответ дан 24 November 2019 в 07:23
поделиться

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

Двоичное представление 1234.5 выглядит примерно так

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

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

01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000

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

См. эту статью Википедии для представления с плавающей запятой в соответствии с IEEE754.

20
ответ дан 24 November 2019 в 07:23
поделиться

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

7
ответ дан 24 November 2019 в 07:23
поделиться

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

7
ответ дан 24 November 2019 в 07:23
поделиться