0

I have following program.

int main () {
    int a = 1;
    long long b = 100000000;
    printf("size of a is: %d \t sizeof b is:%d  \n",sizeof(a),sizeof(b));
    printf("a= %d b=%d a=%d \n", a, b, a);
    printf("a= %d b=%Ld a=%d \n", a, b, a);
    b = 10000000000;
    printf("a= %d b=%d a=%d \n", a, b, a);
    printf("a= %d b=%Ld a=%d \n", a, b, a);
}

When I compile it with gcc -m32 output is

size of a is: 4      sizeof b is:8  
a= 1 b=100000000 a=0 
a= 1 b=100000000 a=1 
a= 1 b=1410065408 a=2 
a= 1 b=10000000000 a=1 

but when it is compiled with gcc -m64 output is.

size of a is: 4      sizeof b is:8  
a= 1 b=100000000 a=1 
a= 1 b=100000000 a=1 
a= 1 b=1410065408 a=1 
a= 1 b=10000000000 a=1 

Why does it show wrong values while printing third printf argument (a)?

My gcc version is

priyanka@priyanka-N551JB:~$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
priyanka
  • 19
  • 3
  • 2
    It is undefined behaviour to call printf with format identifier that does not match the type. So the output of printf is not garantted to be anything. Once you incorrectly use %d to print b, then printfs output is undefined. Turn on compiler warnings and fix your format specifiers. The fact that it works on the 64bit is merely luck of the implementation. – Secto Kia Oct 08 '16 at 03:44
  • @SectoKia ok, but why does value of `a` changes (going from first argument to third) in 32 bit compiler? – priyanka Oct 08 '16 at 03:48
  • @priyanka I wouldn't say that `a`'s value changed. What happened was that printf got confused, and didn't print `a`'s value properly. It got confused because you lied to it. – Steve Summit Oct 08 '16 at 03:54
  • 1
    @priyanka ok? Read that again. Stop trying to make sense of the senseless. You're looking for sense (definition) where there is none. That is seemed to "work" on a 64bit compiler was **unlucky**, not lucky. It lulls you into a false sense of proper code, leading you to conclude *observed* behavior was *defined* behavior. The two are *not* synonymous. – WhozCraig Oct 08 '16 at 03:55
  • That will depend entirely on the way its coded. Most likely on the 32bit version the stack was filled with 4+8+4=16 bytes. Then prinft read only 12 bytes (thinking it was 3 lots of 4 bytes). Hence the second a is actually printing out as the lower half of b. Where as on a 64bit system, most likely the optimiser decided to re-order the parameters to be 4+4+8 (a,a,b) isntead of 4+8+4 (a,b,a) because it wants to keep the 8 byte b long long value alligned to a memory address divisible by 8, so it can be read with 1 64bit insturction instead of two. Of course this is complete speculation..... – Secto Kia Oct 08 '16 at 03:57
  • See my answer for some discussion of how a mistake on one thing (`b`'s format specifier) can affect other things (like how `a`'s value is printed). – Steve Summit Oct 08 '16 at 04:18
  • Possible duplicate of [How to printf long long](http://stackoverflow.com/questions/6400180/how-to-printf-long-long) – Thomas Dickey Oct 08 '16 at 12:56
  • @ThomasDickey not a dup. my question is not about long long. but about subsequent int. – priyanka Oct 08 '16 at 16:39
  • Possible duplicate of [What happens when I use the wrong format specifier?](https://stackoverflow.com/questions/16864552/what-happens-when-i-use-the-wrong-format-specifier) – phuclv Jan 14 '18 at 03:25

1 Answers1

3

You must print long long values using %lld. You cannot print them using %d. If you try to print them using %d it won't work. (It turns out %Ld isn't right, either, although it sounds like gcc is letting you get away with it.)

The number 10000000000 requires 34 bits to represent it. As you've discovered, it will not fit in a 16-bit or 32-bit plain int. However, it will fit in a 64-bit long long int.

It's difficult to know exactly what happens when you try to print a 64-bit long long using %d. You can imagine that 8 bytes get pushed on the stack, and %d pops 4 of them off. Therefore, the other four are still left on the stack, so they're what gets popped for the third %d, not a's actual value. This isn't necessarily exactly what happens, in actuality it's likely to be more complicated than that. And the complications might very easily depend on whether you're compiling in 32 or 64 bit mode.


This ends up being a small, simple illustration of an important point: when a program uses undefined behavior, potentially all aspects of the program become undefined. When you do something really wrong, like trying to print b's long long value using %d, what goes wrong is not only that b's value is printed improperly -- other things go wrong, too.

Here's an analogy. Suppose you buy a brand-new racing bicycle with thin, fast tires. The salesman reminds you that it's a road bike, for riding on smooth paved roads only. If you try to ride it off-road, the salesman warns you, the tires are likely to pop if you hit a rock.

Now, suppose you do ride the bike off the road. And suppose you go over a rock, and the tire pops, and because of that you lose control, and crash, and bend the handlebars, and also get a cut on your forehead. Suppose you go back to the bike shop and say, "Okay, I rode the bike off the road, and the tire popped like you said. But can you explain why the handlebars got bent, and I got this cut on my head?"

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • The issue OP is asking for isn't with `b`, but with `a` being equal to 2 when the 32-bit option is used. – AntonH Oct 08 '16 at 03:48
  • @AntonH yes, and also why is it 0 in the case of first printf. – priyanka Oct 08 '16 at 03:53
  • @AntonH Right, although the real answer is that this is how undefined behavior works: there's a mismatch between `b`'s type and the printf format specifier used to print it, and that mismatch spreads to other parts of the program, including how `a` is printed. But I've updated my answer. – Steve Summit Oct 08 '16 at 03:53
  • @priyanka I actually never noticed the `0` on the first one, hah. – AntonH Oct 08 '16 at 03:56
  • @SteveSummit thanks for explanation ` You can imagine that 8 bytes get pushed on the stack`. How do I find out about what exactly happens in printf, any references? – priyanka Oct 08 '16 at 03:57
  • @priyanka I don't have any references to cite, sorry. It is likely to depend on the compiler, and the processor, and the mode (32 or 64 bit). Do a web search for "variable length argument list calling conventions". (Or, the other answer is, you don't need to know, because as long as your code is correct, the compiler takes care of all this for you, and you don't need to worry about it, and everything just works.) – Steve Summit Oct 08 '16 at 04:10
  • Actually it depends on the reasons why do you need this information. If you want to get into the wonderful world of compilers and code translation, you should look on the disassembled code and carefully inspect corresponding instructions. But mind that those instructions are compiler-, target platform and optimization flags dependent so in a different compiler, different system or different `-O` level you might get completely different results. – user3159253 Oct 08 '16 at 04:17
  • The `L` modifier is only for use with `long double` according to [`printf()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html). – Jonathan Leffler Oct 08 '16 at 04:46
  • @JonathanLeffler Thanks, I meant to double-check that. – Steve Summit Oct 08 '16 at 05:04
  • Thanks. I learnt more about this issue at this link http://www.cis.syr.edu/~wedu/Teaching/cis643/LectureNotes_New/Format_String.pdf – priyanka Oct 08 '16 at 05:27
  • This answer mostly wrong. If the wing amount of bytes was popped if the stack, the program would crash when returning from subroutine. All you can really say is that a bunch of bytes are put on the stack and then taken off later, inbetween printf reads then. Also it's not undefined – Secto Kia Oct 19 '16 at 11:13
  • @SectoKia Huh? What's not undefined? – Steve Summit Oct 19 '16 at 22:43
  • not only `long long` but `sizeof` is also printed incorrectly. [It must be printed using `%zu`](https://stackoverflow.com/q/940087/995714) – phuclv Jan 14 '18 at 03:27