I am working on a 32-bit system. When I try to print more than one 64 bit value in a single printf, then it cannot print any further (i.e. 2nd, 3rd, ...) variable values.
You need to use the correct format:
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
int main(void)
{
uint64_t a = 0x12345678;
uint64_t b = 0x87654321;
uint64_t c = 0x11111111;
printf("a is %#" PRIx64
" & b is %#" PRIx64
" & c is %#" PRIx64 "\n",
a, b, c);
return EXIT_SUCCESS;
}
Output:
a is 0x12345678 & b is 0x87654321 & c is 0x11111111
As appropriate for a forum named Stack Overflow, the cause of the unexpected printf()
output is due to stack misalignment. The size mismatch between the %x
conversion specification and function argument a
causes the misalignment.
When compiling the statement
printf("a is %x & b is %llx & c is %llx",a,b,c);
the compiler generates machine code that pushes the function arguments on the stack in right-to-left order.
The compiler uses the variable declarations, not the format string, to determine the data size of each argument on the stack (except possibly for generating warnings). In an x86 CPU (as in most machines) the stack pointer decrements with every push. When entering the printf()
library function, the stack therefore has the following layout:
00A4: ... 00A0: 00000000 009C: 11111111 Variable 'c' pushed on the stack as uint64 0098: 00000000 0094: 87654321 'b' pushed on the stack as uint64 0090: 00000000 008C: 12345678 'a' pushed on the stack as uint64 0088: <pointer to format string> 0084: <return address>
The top-of-stack address of 0084 is arbitrary for this example.
Since all three variables are declared as uint64_t
, the compiled code pushes these variables on the stack as 64-bit values. For a little-endian machine such as an x86 CPU, the high bytes of each uint64
value end up in the higher addresses.
The implementation of printf()
uses the format string to determine the number of and sizes of the arguments on the stack. Unlike the compiler, printf()
receives no information about the original variable declarations. The first conversion specification is %x
, so printf()
expects a
to be a 32-bit value, and therefore, printf()
parses the stack layout as follows:
00A4: ... 00A0: 00000000 009C: 11111111 0098: 00000000 '%llx' reads 'c' as uint64, but from the wrong address 0094: 87654321 0090: 00000000 '%llx' reads 'b' as uint64, but from the wrong address 008C: 12345678 '%x' causes printf() to read 'a' as a uint32 0088: <pointer to format string> 0084: <return address>
The stack misalignment explains why a
prints 12345678 as expected, but b
and c
have been effectively left-shifted by 32 bits to 8765432100000000 and 1111111100000000.
Correcting the first %x
conversion specification or casting argument a
to uint32 should fix the problem.
Use:
"%lli" for int64_t
"%llu" for uint64_t
"%llx" for hex
"%llX" for HEX
Have a look inside "inttypes.h".
It prints them all on my computer, but there are three compile time warnings since %llx
expects a long long unsigned int
.
Are you sure you need to be using 64 bit types though? All three of your hexcodes are only 32 bits. Maybe you could just use 32 bits and do:
unsigned int a = 0x12345678;
unsigned int b = 0x87654321;
unsigned int c = 0x11111111;
printf("a is %x & b is %x & c is %x",a,b,c);
(Or use the stdint equivalent of 32bit unsigned int)
Unless you need them to be 64 bits so you can add more bits to them later.
You should use the macros defined in <inttypes.h>
printf("a is %"PRIx64" & b is %"PRIx64" & c is %"PRIx64"\n",a,b,c);
It is ugly as hell but it's portable. This was introduced in C99, so you need a C99 compliant compiler.