400

C99 standard has integer types with bytes size like int64_t. I am using Windows's %I64d format currently (or unsigned %I64u), like:

#include <stdio.h>
#include <stdint.h>
int64_t my_int = 999999999999999999;
printf("This is my_int: %I64d\n", my_int);

and I get this compiler warning:

warning: format ‘%I64d’ expects type ‘int’, but argument 2 has type ‘int64_t’

I tried with:

printf("This is my_int: %lld\n", my_int); // long long decimal

But I get the same warning. I am using this compiler:

~/dev/c$ cc -v
Using built-in specs.
Target: i686-apple-darwin10
Configured with: /var/tmp/gcc/gcc-5664~89/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5664)

Which format should I use to print my_int variable without having a warning?

fearless_fool
  • 33,645
  • 23
  • 135
  • 217
rtacconi
  • 14,317
  • 20
  • 66
  • 84

7 Answers7

569

For int64_t type:

#include <inttypes.h>
int64_t t;
printf("%" PRId64 "\n", t);

for uint64_t type:

#include <inttypes.h>
uint64_t t;
printf("%" PRIu64 "\n", t);

you can also use PRIx64 to print in hexadecimal.

cppreference.com has a full listing of available macros for all types including intptr_t (PRIxPTR). There are separate macros for scanf, like SCNd64.


A typical definition of PRIu16 would be "hu", so implicit string-constant concatenation happens at compile time.

For your code to be fully portable, you must use PRId32 and so on for printing int32_t, and "%d" or similar for printing int.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
ouah
  • 142,963
  • 15
  • 272
  • 331
  • 20
    Complete list of formatting macro constants: http://en.cppreference.com/w/cpp/types/integer – Masood Khaari May 14 '13 at 10:45
  • 14
    And, if using C++ on Linux, be sure to `#define __STDC_FORMAT_MACROS` before including `inttypes.h`. – csl Nov 28 '14 at 08:50
  • 21
    `PRId64` is a macro which internally translates to `"lld"`. So, it is as good as writing `printf("%lld\n", t);` See description : http://www.qnx.com/developers/docs/6.5.0/index.jsp?topic=%2Fcom.qnx.doc.dinkum_en_c99%2Finttypes.html – Gaurav Aug 14 '15 at 11:32
  • 43
    @Gaurav, that's true on some platforms, but not on all. On my amd64 Linux machine, for instance, PRId64 is defined as `ld`. Portability is the reason for the macro. – Ethan T Jun 28 '16 at 15:06
  • 24
    I think with some extra effort they could have made it even more obnoxious – Pavel P Oct 27 '17 at 23:35
  • Apparently there is a mismatch in header code of gcc collection, which leads to PRId64 be defined on 64 bit linux as "ld" and on 32 bit as "lld", which is incorrect. – Swift - Friday Pie Oct 30 '18 at 12:35
  • @PavelP Indeed. This is hideous. I've never done it this way. And I had thought there was feature creep already. This is ghastly. – Pryftan Dec 03 '19 at 22:57
  • 2
    @Swift-FridayPie. `long` has 32 bits on 32-bit Linux systems and 64 bits on 64-bit Linux systems. That's why `PRId64` is `"lld"` and `"ld"` respectively. This allows `long long` to get longer than `long` in the future. On shortsighted platforms, `long` has 32 bits even on 64-bit systems, which makes `PRId64` be `"%lld"` on both architectures. – Shahbaz Apr 27 '20 at 19:22
  • @Shahbaz depends on configuration . All distribs of 64bit I dealt with long is 32bit but this cannot be relied on. You have to rely on guarantred size types and macroses. "lld" format is not portable at all, not all compilers support it. – Swift - Friday Pie May 05 '20 at 18:20
  • Why not to use just `%ld` (long integer) for both `int64_t` and `unit64_t`? – vmemmap Aug 24 '20 at 15:41
  • 1
    @r0ei Because `long` is not guaranteed to be 64 bits. – Andrew Henle Jan 22 '21 at 15:16
  • 1
    @Roi You also should not be using `%ld` (or any specifier containing `d`) on unsigned types. The equivalent is `%lu`. Note the reason: `printf("%ld\n", ULONG_MAX);` will print `-1` on all modern platforms; obviously a negative number is not the maximum value of `unsigned long`. C does not have any information at runtime about the type of arguments to `printf` except what you give it. Format specifiers tell both the desired output format *and* type of the supplied argument. Using the wrong format specifier may work on some platforms but break on others, making your program not portable. – kbolino Dec 06 '21 at 23:18
  • https://en.cppreference.com/w/c/types/integer – Adam Jan 29 '23 at 19:34
79

The C99 way is

#include <inttypes.h>
int64_t my_int = 999999999999999999;
printf("%" PRId64 "\n", my_int);

Or you could cast!

printf("%ld", (long)my_int);
printf("%lld", (long long)my_int); /* C89 didn't define `long long` */
printf("%f", (double)my_int);

If you're stuck with a C89 implementation (notably Visual Studio) you can perhaps use an open source <inttypes.h> (and <stdint.h>): http://code.google.com/p/msinttypes/

pmg
  • 106,608
  • 13
  • 126
  • 198
  • When using msinttypes from the code.google.com link, I need to define __STDC_FORMAT_MACROS. See http://stackoverflow.com/questions/8132399/how-to-printf-uint64-t. – ariscris May 28 '14 at 16:49
  • 1
    Thanks for the heads up, @ariscris. It appears that macro is only required for C++ though. The definitions in the code linked to are inside a `#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)` – pmg May 28 '14 at 17:08
23

With C99 the %j length modifier can also be used with the printf family of functions to print values of type int64_t and uint64_t:

#include <stdio.h>
#include <stdint.h>

int main(int argc, char *argv[])
{
    int64_t  a = 1LL << 63;
    uint64_t b = 1ULL << 63;

    printf("a=%jd (0x%jx)\n", a, a);
    printf("b=%ju (0x%jx)\n", b, b);

    return 0;
}

Compiling this code with gcc -Wall -pedantic -std=c99 produces no warnings, and the program prints the expected output:

a=-9223372036854775808 (0x8000000000000000)
b=9223372036854775808 (0x8000000000000000)

This is according to printf(3) on my Linux system (the man page specifically says that j is used to indicate a conversion to an intmax_t or uintmax_t; in my stdint.h, both int64_t and intmax_t are typedef'd in exactly the same way, and similarly for uint64_t). I'm not sure if this is perfectly portable to other systems.

pjhsea
  • 841
  • 9
  • 13
  • 15
    If `%jd` prnts an `intmax_t`, the correct invocation would be `printf("a=%jd (0x%jx)", (intmax_t) a, (intmax_t) a)`. There is no guarantee that `int64_t` and `intmax_t` are the same type, and if they aren't, the behavior is undefined. – user4815162342 Apr 25 '13 at 17:56
  • 4
    You can portably use `%jd` to print `int64_t` values *if* you explicitly convert them to `intmax_t` before passing them to `printf`: `printf("a=%jd\n", (intmax_t)a)`. This avoids the (IMHO) ugliness of the `` macros. Of course this assumes that your implementation supports `%jd`, `int64_t`, and `intmax_t`, all of which were added by C99. – Keith Thompson Aug 12 '13 at 19:03
  • 3
    @KeithThompson 'Ugliness' is putting it far far far far too kindly mate. It's absolutely hideous. It's ghastly. It's nauseating. It's embarrassing is what it is. Or at least they should be embarrassed, the lot that introduced this. I've never seen these macros but do what this answer and the comments - yours included - suggest. – Pryftan Dec 03 '19 at 22:59
  • @Pryftan I don't *quite* find them quite as ugly as you do -- and I'm not at all sure how they could be defined in a less ugly manner without language changes. – Keith Thompson Dec 04 '19 at 02:28
  • @KeithThompson Well I'm thankful you at least put a stress on the word 'quite'. Well actually it doesn't matter. I don't see why the macros have to be there though. As you say you can portably ... Etc. But then I also find that the increase in the number of keywords has got out of hand too. – Pryftan Dec 14 '19 at 20:46
  • @Pryftan: The macros make it possible to print values of these types without converting to a wider type, which could have significant performance implications in some contexts. In the absence of overloading, you have to encode the type name in the macros. I/O is expensive enough that integer conversion probably gets lost in the noise, but converting to `[u]intmax_t` might be expensive on some systems. I can't think of a better way to achieve the same effect without changing the language (though you might be able to throw something together using `_Generic`). – Keith Thompson Dec 14 '19 at 21:10
  • @KeithThompson Well okay I know what you mean. I get the point. I still think that it's hideous and there could be better options. Unfortunately in this world we often don't have better options. As for better options what I mean is exact format specifiers. But that's neither here nor there I think. – Pryftan Feb 01 '20 at 18:01
  • @KeithThompson A bit late here, but a length modifier like `yN` where the format specifier for a `uint64_t` would be `%y64u` would have been much better than the macro solution that is extremely hard to read and a pain to code since it requires breaking the string and using implicit string concatenation. And the committee has gone there before with the `z` as a length modifier for `size_t` . – Andrew Henle Jan 22 '21 at 15:24
  • @AndrewHenle Possibly, but if you want to cover weird systems you can't assume that `uint64_t` exists. You can assume that `uint_least64_t` and `uint_fast64_t` exist, but if the format specifier is for one of those you might have to cast a `uint64_t` argument. Likewise for 8, 16, 32. – Keith Thompson Jan 22 '21 at 18:31
  • @KeithThompson So `ylN` and `yfN`? There are a lot of letters available that can be used to make unique patters that are a lot more meaningful, readable, and maintainable. The macro approach completely breaks "normal" `printf()` patterns. "But those types are optional" is a weak-at-best argument, as the `[u]intN_t` identifiers are all reserved anyway. – Andrew Henle Jan 22 '21 at 18:44
  • @AndrewHenle I guess that their reasoning was to avoid incurring extra overhead in `printf` implementations, which introducing greater verity of length modifiers would do. Their solution, as ugly as it is, resolves to one of the already-supported modifiers at compile time. – Yakov Galka Jan 23 '22 at 01:48
18

Coming from the embedded world, where even uclibc is not always available, and code like

uint64_t myval = 0xdeadfacedeadbeef; printf("%llx", myval);

is printing you crap or not working at all -- i always use a tiny helper, that allows me to dump properly uint64_t hex:

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

char* ullx(uint64_t val)
{
    static char buf[34] = { [0 ... 33] = 0 };
    char* out = &buf[33];
    uint64_t hval = val;
    unsigned int hbase = 16;

    do {
        *out = "0123456789abcdef"[hval % hbase];
        --out;
        hval /= hbase;
    } while(hval);

    *out-- = 'x', *out = '0';

    return out;
}
ataraxic
  • 2,157
  • 2
  • 17
  • 10
  • 1
    Shouldn't buf be 34+1 in size? The char array doesn't get null terminated atm. – Bjartskular Jan 19 '22 at 12:51
  • 1
    @Bjartskular Is correct that this function doesn't properly nul terminate. A better fix would be to simply change `out` to initially point at `&buf[32]`, since there are already about twice as many char's as maximally required here. Also, using static variables like this is begging for problems down the line (e.g. - multithreading). It'd be better if `buf` was passed in as a parameter with caller requirements on how big it must be (and we nul terminate). – jschultz410 Jan 25 '23 at 21:58
12

In windows environment, use

%I64d

in Linux, use

%lld
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
benlong
  • 668
  • 1
  • 7
  • 16
  • 20
    `%lld` is the format for `long long int`, which is *not* necessarily the same as `int64_t`. `` has a macro for the correct format for `int64_t`; see [ouah's answer](http://stackoverflow.com/a/9225648/827263). – Keith Thompson Aug 12 '13 at 19:05
  • @KeithThompson However, since `long long` is at least 64-bit, `printf("%lld", (long long)x);` ought to work, except perhaps for -0x8000000000000000, which could not be representable as a `long long` if that type is not using two's complement. – Pascal Cuoq Aug 12 '13 at 20:54
  • @PascalCuoq: Yes, it should work with the cast (and the exception you mention is very unlikely, applying only to a system that supports two's-complement but doesn't use it for `long long`). – Keith Thompson Aug 12 '13 at 21:10
0

Stumbled upon this question when I was looking for a way to display 64 bit number in hex:

Found out that you can use:

0x%016llx - at least works with my compiler (aarch64 GCC 7.3.0)

HarshaD
  • 243
  • 2
  • 9
-8

//VC6.0 (386 & better)

    __int64 my_qw_var = 0x1234567890abcdef;

    __int32 v_dw_h;
    __int32 v_dw_l;

    __asm
        {
            mov eax,[dword ptr my_qw_var + 4]   //dwh
            mov [dword ptr v_dw_h],eax

            mov eax,[dword ptr my_qw_var]   //dwl
            mov [dword ptr v_dw_l],eax

        }
        //Oops 0.8 format
    printf("val = 0x%0.8x%0.8x\n", (__int32)v_dw_h, (__int32)v_dw_l);

Regards.

Daniel Ag
  • 1
  • 1