This answer attempts to resolve some of the change options. This is the answer to Daniel Fisher's question and some comments on it.
Since I do not work with Linux, I cannot give a definitive answer. With a printf later in a large application there would be many sources of potential variation. At the beginning of a small application, there should be only a few.
Address space location randomization (ASLR) is one: the operating system deliberately randomly reorders some memory to prevent malware knowing which addresses to use. I do not know if this has Linux 3.4.4-2.
The other is environment variables. Shell environment variables are copied into the processes that it spawns (and are accessible through the getenv procedure). Some of them may change automatically, so they will have slightly different meanings. This is unlikely to directly affect what printf sees when it tries to use a missing integer argument, but there may be cascading effects.
There may be a shared library loader that starts either before calling main , or before calling printf . For example, if printf is in a shared library and not embedded in your executable, then calling printf will most likely result in a call to the stub procedure that calls the bootloader. The loader scans the shared library, finds the module containing printf , loads the module into the address space of the process, changes the stub so that it calls the recently loaded printf right in the future (instead of calling the loader), and calls printf . As you can imagine, this can be a fairly extensive process and includes, among other things, finding and reading files on disk (all directories for access to the shared library and shared library). It is possible that some caching or file operations on your system result in little behavior in the bootloader.
So far, I have endorsed the ASLR as the most likely candidate of the above. The last two are likely to be fairly stable; values ββusually change sometimes rather than often. ASLR will change every time, and just leaving the address in the register is enough to explain the behavior of printf .
Here is an experiment: after the initial printf insert another printf using this code:
printf("%d\n", 2.443); int a; printf("%p\n", (void *) &a);
The second printf prints the address of a , which is most likely on the stack. Run the program two or three times and calculate the difference between the value printed by the first printf and the value printed by the second printf . (The second printf will most likely print in hexadecimal, so it would be convenient to change the first to "% x" to make it hexadecimal.) If the value printed by the second printf varies from run to run, then your program is experiencing ASLR. If the values ββchange from run to run, but the difference between them remains constant, then the value that printf occurred in the first printf is some address in your process that remains lying after the program was initialized.
If address a changes, but the difference does not remain constant, you can try changing int a; on static int a; to compare if the first value compares with the other part of your address space the best result.
Naturally, none of this is useful for writing reliable programs; this is just an educational question about how loading and initializing a program works.