3

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?

Claudio Cortese
  • 1,372
  • 2
  • 10
  • 21
PKG
  • 79
  • 4

6 Answers6

2

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...

chqrlie
  • 131,814
  • 10
  • 121
  • 189
1

The %f specifier needs to be matched by a floating-point parameter (float or double), you're giving it ints instead. Not matching the type is undefined behaviour, meaning it could do anything, including printing different results everytime.

Hope this helped, good luck :)

Edit: Thanks chqrlie for the clarifications!

Lutopia
  • 113
  • 8
  • 2
    `%f` actually expects a `float` or a `double` argument. `float` arguments are promoted to `double` when passed to `printf` (and any other variadic function). `'a'` is not a `char` in C, it is an `int` value. Btw a `char` value would be implicitly promoted to `int` when passed to `printf`. – chqrlie Jan 29 '17 at 13:52
1

Unpredictable behavior.

When you try to print value using mismatch format specifier, compiler give an unpredictable output.The behavior on using %f as the format specifier for an char and int is undefined.

Use correct format specifier in your program according yo data type:

printf("%d\n", 'a'); // print ASCII value
printf("%d\n", a);
msc
  • 33,420
  • 29
  • 119
  • 214
1

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.

myaut
  • 11,174
  • 2
  • 30
  • 62
0

First of all, gcc should give a warning for the above code. This is because of the mismatch in the format specifier.

Mismatched formatting (printf() as well as scanf()) will give unpredictable behavior in C. This is in spite of the fact that gcc is expected to take care possible type conversions like int to float implicitly.

Here is are two nice references.
https://stackoverflow.com/a/1057173/4954434
https://stackoverflow.com/a/12830110/4954434

Following will work as expetced.

#include <stdio.h>

int main(void)
{
    int a = 50000;
    float b = 'a';
    printf("b = %f\n", (float)'a');
    printf("a = %f\n", (float)a);
    return 0;
}
Community
  • 1
  • 1
Jithin Pavithran
  • 1,250
  • 2
  • 16
  • 41
0

The main difficult you are having is the data type you are using. When you create a variable you are telling the size the memory will have to reserve to work properly. Like char have a size of 1 byte, int equal 4 byte and float 32 byte. It's important to use the same data type to not have unpredictable result.

char a = 'a';
printf("%c",a);

int b = 50000;
printf("%d",b);

float c = 5.7;
printf("%f", c);

For more information: C-Variables

Bortoli
  • 9
  • 3