8

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.

example:

uint64_t a = 0x12345678;
uint64_t b = 0x87654321;
uint64_t c = 0x11111111;

printf("a is %llx & b is %llx & c is %llx",a,b,c);

Why can this printf not print all values?

I am modifying my question

printf("a is %x & b is %llx & c is %llx",a,b,c);

by doing this result is : a is 12345678 & b is 8765432100000000 & c is 1111111100000000

if i am not printing a's value properly then why other's value's are gona change??

Jeegar Patel
  • 26,264
  • 51
  • 149
  • 222
  • 4
    What is the output (or error) that you're getting? – Chris Lutz Jul 27 '11 at 20:22
  • 2
    Actually, it works: http://ideone.com/um0QL – Vlad Jul 27 '11 at 20:25
  • 1
    You cannot use `ll` for `uint64_t`. You can only use `ll` for `long long` types. You should use the [`` macros](http://en.cppreference.com/w/cpp/types/integer)! – Kerrek SB Jul 27 '11 at 20:25
  • When I include your code snippet in a complete program, it produces the expected output. Please provide a minimal, complete sample program along with your expected output and the output you actually see. For an explanation of who to create a minimal complete program, and why that is a useful tool, see http://sscce.org. – Robᵩ Jul 27 '11 at 20:28
  • What compiler, os, and compiler options are you using? – Robᵩ Jul 27 '11 at 20:28
  • @Kerrek SB: Xcode 4.1 tells me `%llx` is correct for an uint64_t. – Rudy Velthuis Jul 27 '11 at 20:42
  • @Rudy: That's coincidence, not portable! – Kerrek SB Jul 27 '11 at 20:57
  • @Kerrek: Yes, you are right. PRIx64 resolves to "llx" here, but PRIx64 is portable and "llx" is not. – Rudy Velthuis Jul 27 '11 at 21:28
  • @Rudy: Well, `llx` is also portable, it just refers to a different type! :-) For `unsigned long long int` you print `llu` or `llx`, for `unsigned long int` you print `lu` or `lx`, and for `unsigned int` you print `u` or `x`. Never mind that those are all bitwise identical, but they're different *types* in the language. – Kerrek SB Jul 27 '11 at 21:33
  • I meant it is not portable when not dealing with a long long type. – Rudy Velthuis Jul 27 '11 at 21:37
  • printf("a is %x & b is %llx & c is %llx",a,b,c); by doing this result is : a is 12345678 & b is 8765432100000000 & c is 1111111100000000 if i am not printing a's value properly then why other's value's are gona change?? – Jeegar Patel Jul 28 '11 at 05:26

5 Answers5

15

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.

Vinicius Kamakura
  • 7,665
  • 1
  • 29
  • 43
  • Since this is accepted, I wonder what the format for `PRIx64` is on Xcode 4.1 if it isn't "llx"? – Michael Burr Jul 27 '11 at 20:58
  • I don't have access to that compiler but if you do, you could try: `printf("PRIx64 is %s\n", PRIx64")` or the shorter `printf("PRIx64 is "PRIx64"\n");` – Vinicius Kamakura Jul 27 '11 at 21:03
  • 2
    You are completely right to insist on `PRIx64` etc. But my guess of what makes the difference for the OP is just the `\n` at the end of the format string... – Jens Gustedt Jul 27 '11 at 21:17
  • @Jens You might be just right :P I added it to my answer without even considering that, I guess it is just reflex :) – Vinicius Kamakura Jul 27 '11 at 21:19
  • 1
    In Xcode 4.1, PRIx64 is `#define PRIx64 __PRI_64_LENGTH_MODIFIER__ "x"` and `#define __PRI_64_LENGTH_MODIFIER__ "ll"`. – Rudy Velthuis Jul 27 '11 at 21:25
  • printf("a is %x & b is %llx & c is %llx",a,b,c); by doing this result is : a is 12345678 & b is 8765432100000000 & c is 1111111100000000 if i am not printing a's value properly then why other's value's are gona change?? – Jeegar Patel Jul 28 '11 at 05:27
  • @patel it will bug because `printf` will pop from the stack incorrect numbers of bytes. a is 8 bytes, but using `%x` removes only 4. so the other 4 remain on the stack, then `%llx` removes 8 bytes, but they are wrong, because 4 are from `a` and 4 from `b`. The same happens with the next `%llx`. – Vinicius Kamakura Jul 28 '11 at 14:47
11

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
XYZ
  • 126
  • 2
  • printf("a is %x & b is %llx & c is %llx",a,b,c); by doing this result is : a is 12345678 & b is 8765432100000000 & c is 1111111100000000 if i am not printing a's value properly then why other's value's are gona change?? – Jeegar Patel Jul 28 '11 at 05:28
  • I get warnings using %#" PRIx64 "..." so I just removed the # and it works fine. (msys2 gcc 5.3.0) – Jimmio92 May 30 '16 at 18:34
  • 1
    What does the `#` do (as in `%#`) ? – polynomial_donut Jan 03 '18 at 17:05
2

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.

Paul
  • 139,544
  • 27
  • 275
  • 264
1

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.

Fred Schleifer
  • 506
  • 1
  • 7
  • 7
0

Use:

"%lli" for int64_t
"%llu" for uint64_t
"%llx" for hex
"%llX" for HEX

Have a look inside "inttypes.h".

nvd
  • 2,995
  • 28
  • 16