Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How different data type variable inside a printf statement affects each other relatively in there printing order

Tags:

c

printf

When I executed this code snippet:

void main(){
    float a=3;
    int b=5;
    printf( "%d %d \n", a, b);
}

I got output as

0 1074266112 

and when i changed the order of printing i.e.,

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

I got this as output:

5 0

Why?

like image 802
Anks Avatar asked Dec 25 '22 10:12

Anks


2 Answers

As your specifiers don't match the actual values, you invoke undefined behaviour. That means just anything can happen and, especially, the behaviour could change between invocations of the program (if the format specifiers read more data than actually provided) or at least between compiler settings.


What internally probably happens depends on many factors, such as the length of int values and much more. In any case, it is something you cannot rely on.

What really happens here is: floats are automatically promoted to double when being passed to a variadic function, changing their length to 8 bytes.

I modified your program in this way:

#include <stdio.h>

void main(){
    float a=3;
    int b=5;
    printf("%08x %08x %08x\n", a, b);
    printf("%08x %08x %08x\n", b, a);
    printf("%d %d %d\n", a, b);
    printf("%d %d %d\n", b, a);
}

which gives the output

00000000 40080000 00000005
00000005 00000000 40080000
0 1074266112 5
5 0 1074266112

So we exactly see the values resp. bytes being passed via the stack to printf(). As these values are swapped due to the endianness (they are visually swapped when interpreted via %08x), I really have the bytes

00 00 00 00  00 00 08 40  05 00 00 00
05 00 00 00  00 00 00 00  00 00 08 40

If we now use the wrong specifiers, we get the mapping

00 00 00 00 -> 00000000 -> 0
00 00 08 40 -> 40080000 -> 1074266112
05 00 00 00 -> 00000005 -> 5

which is then output.

If I omit one %d, the respectively last value is omitted as well, leading to

0 1074266112
5 0

in turn.

So the reason why your b value seems to change is that in the first case, you really get the "other" part of your a value.

like image 154
glglgl Avatar answered Dec 28 '22 01:12

glglgl


You code does technically invoke undefined behaviour; still there is clear logic behind the two outputs.

It has to do with variadic function and automatic type promotions.

Everytime you pass a float to a variadic function it gets automatically promoted to double. The printf specifier %f is always interpreted as %lf. you can try this yourself, output is always double.

First example:

float a=3;
int b=5;
printf( "%d %d \n", a, b);

( int type takes 4 bytes on you system )

You pass a float which gets promoted to a double and takes 8 bytes of stack, and a integer which takes 4 bytes. Then you try to print the first 8 bytes on the stack( with %d of 4 bytes twice ) and you get the first 4 and last 4 bytes of the ( now )double. The integer in not read.

Second example:

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

This is different as you first pass the integer which gets printed correctly and then you only print the first 4 bytes of the double.

like image 44
this Avatar answered Dec 27 '22 23:12

this