возврат функции изменен, как написано непосредственно в инструкции printf - PullRequest
2 голосов
/ 08 апреля 2020
#include <stdio.h>
#include <math.h>

int main() {
    printf("%d\n", pow(3546, 0));   
    return 0;
}

Приведенный выше код печатает значение 0

В то время как приведенный ниже код печатает значение 1

#include <stdio.h>
#include <math.h>

int main() {
    int a  = pow(3546, 0);
    printf("%d\n", a);
    return 0;
}

Почему это так? Даже если они эквивалентны.

Ответы [ 3 ]

0 голосов
/ 08 апреля 2020

pow возвращает результат типа double, а %d не является корректным спецификатором преобразования, используемым для его форматирования. Результирующее поведение не определяется стандартом C.

Чтобы напечатать double, вы можете использовать %g или %f, среди других опций:

printf("%g\n", pow(3456, 0));
printf("%f\n", pow(3456, 0));

В int a = pow(3546,0); значение double автоматически преобразуется в int для инициализации int a, а затем печатается, что int с %d является правильным.

0 голосов
/ 08 апреля 2020

Нет эквивалентности. Последняя функция явно преобразует число в int перед печатью, тогда как первая приводит к UB, пытаясь напечатать число с плавающей запятой, используя неправильный спецификатор формата - вам повезло получить 0, возможно, вы получили произвольный номер.

Пожалуйста, включите все предупреждения на вашем компиляторе, он должен жаловаться на использование неправильного формата для неправильного типа данных.

0 голосов
/ 08 апреля 2020

Как уже упоминалось в в этом ответе , printf использует спецификаторы формата, чтобы знать, что вытолкнуть из стека (%d равно sizeof(int), что в моей системе составляет 4 байта).

( Редактировать: Как указано в комментариях rici , это не обязательно будет стек (на x86 он находится в регистре ЦП большую часть время). В стандарте никогда не говорится о реализациях, и именно в этом и заключается эта проблема.)

Небольшой забавный факт: в моем окне Windows 10 было 0 и 1. В моем Xubuntu VBox это было 1 и -2132712864. Таким образом, printf выталкивает только 4 байта, и порядок вашего компьютера портит результат. Из pow (3) manual :

#include <math.h>

double pow(double x, double y);
float powf(float x, float y);
long double powl(long double x, long double y);

Итак, чтобы получить правильный результат в обоих случаях, используйте правильный printf спецификатор формата :

double a = pow(3546, 0);

И:

printf("%lf\n", pow(3546, 0));

Если вы хотите узнать больше о variadi c функциях (таких как printf , которые принимают переменное количество параметров), начните с прочтения справочной страницы API .

#include <stdarg.h>

void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
...