Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different output every time in c?

I am trying to learn C and am very confused already.

#include <stdio.h>

int main(void)
{
    int a = 50000;
    float b = 'a';
    printf("b = %f\n", 'a');
    printf("a = %f\n", a);
    return 0;
}

The above code produces a different output each time with gcc. Why?

like image 215
PKG Avatar asked Feb 17 '26 16:02

PKG


2 Answers

You pass an int value ('a') for a %f format expecting a float or a double. This is undefined behavior, which can result in different output for every execution of the same program. The second printf has the same problem: %f expects a float or double but you pass an int value.

Here is a corrected version:

#include <stdio.h>

int main(void) {
    int a = 50000;
    float b = 'a';

    printf("a = %d\n", a);
    printf("b = %f\n", b);
    printf("'a' = %d\n", 'a');

    return 0;
}

Output:

a = 50000
b = 97.000000
'a' = 97

Compiling with more warnings enabled, with command line arguments -Wall -W -Wextra lets the compiler perform more consistency checks and complain about potential programming errors. It would have detected the errors in the posted code.

Indeed clang still complains about the above correction:

clang -O2 -std=c11 -Weverything fmt.c -o fmt
fmt.c:8:24: warning: implicit conversion increases floating-point precision: 'float' to 'double' [-Wdouble-promotion]
    printf("b = %f\n", b);
    ~~~~~~             ^
1 warning generated.

b is promoted to double when passed to printf(). The double type has more precision than the float type, which might output misleading values if more decimals are requested than the original type afforded.

It is advisable to always use double for floating point calculations and reserve the float type for very specific cases where it is better suited, such as computer graphics APIs, some binary interchange formats...

like image 67
chqrlie Avatar answered Feb 19 '26 06:02

chqrlie


From implementation standpoint, passing floating point numbers (that what %f expects) as variable argument lists (that is what ... means in printf prototype) and integers (that is what 'a' is, specifically of type int) may use different registers and memory layout.

This is usually defined by ABI calling conventions. Specifically, in x86_64, %xmm0 will be read by printf (with unitialized value), but gcc will fill %rdi in printf call.

See more in System V Application Binary Interface AMD64 Architecture Processor Supplement, p. 56

You should note that C is a very low-level language which puts a lot of confusing cases (including integer overflows and underflows, unitialized variables, buffer overruns) on shoulders of implementation. That allows to gain maximum performance (by avoiding lots of checks), but leaves to errors such as this error.

like image 41
myaut Avatar answered Feb 19 '26 06:02

myaut