function return changed as directly written in printf statement

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

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

The above code prints value 0

While the below code prints value 1

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

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

Why is it so? Even though they are equivalent.

3 Answers

There's no equivalence. The latter function explicitly converts the number to int before printing, while the former results in UB by trying to print a floating point number using wrong format specifier -- you're lucky to get 0, you might have gotten an arbitrary number.

Please, turn on all warnings on your compiler, it should complain about using wrong format for the wrong type of data.

pow returns a result of type double, and %d is not a correct conversion specifier to use to format it. The resulting behavior is not defined by the C standard.

To print a double, you can use %g or %f, among other options:

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

In int a = pow(3546,0);, the double value is automatically convert to an int for the initialization of the int a, and then printing that int with %d is correct.

As mentioned in this answer, printf uses the format specifiers to know what to pop off the stack (%d is sizeof(int), which is 4 bytes in my system).

(Edit: As pointed out by rici in the comments, it's not guaranteed to be the stack (on x86 it's in the CPU registers most of the time). The standard never talks about implementations, which is what this problem is all about.)

A small fun fact: in my Windows 10 box it was 0 and 1. In my Xubuntu VBox it was 1 and -2132712864. Therefore, printf is poping only 4 bytes, and the endianess of your machine is screwing the result. From 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);

So, in order to get the correct result in both cases, make use of the correct printf format specifier:

double a = pow(3546, 0);

And:

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

If you want to know more about variadic functions (the ones like printf, which take a variable amount of parameters), start by reading the API manual page.

#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);
Related