604

The printf function takes an argument type, such as %d or %i for a signed int. However, I don't see anything for a long value.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Thomas Owens
  • 114,398
  • 98
  • 311
  • 431
  • Don't use long, it's not portable. https://stackoverflow.com/questions/16859500/mmh-who-are-you-priu64 – MarcH Nov 23 '19 at 01:02
  • 1
    @MarcH — neither is `int` portable. Historically, `int` was a 16-bit value; it has also been a 64-bit value on some machines (Cray, for example). Even the 'exact width types' such as `int64_t` are not 100% portable; they're defined only if the architecture supports such a type. The `int_least64_t` types are as close as it gets to portable. – Jonathan Leffler Nov 04 '22 at 21:04
  • The C11 specification is [§7.21.6.1 The `fprintf` function](http://port70.net/~nsz/c/c11/n1570.html#7.21.6.1) — the entry in [§7.21.6.3 The `printf` function](http://port70.net/~nsz/c/c11/n1570.html#7.21.6.3) largely redirects to ¶7.21.6.1. The POSIX specification is [`printf()`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html). – Jonathan Leffler Nov 04 '22 at 21:08
  • `int` is not portable either yet it can be the best choice in some cases; for instance the index of a small `for` loop does typically not require portability. On the other hand,`long` is not portable _and_ it's never useful and never the best choice. `long` is just bad. If you need something guaranteed to be 32bits or 64bits big then use `uint32_t` or `uint64_t`. Simple. If they're not available on some exotic platform then your code will not compile which is what you want. – MarcH Nov 04 '22 at 21:39
  • On that topic: https://faultlore.com/blah/c-isnt-a-language/ – MarcH Nov 05 '22 at 17:27

7 Answers7

778

Put an l (lowercased letter L) directly before the specifier.

unsigned long n;
long m;

printf("%lu %ld", n, m);
rogerdpack
  • 62,887
  • 36
  • 269
  • 388
postfuturist
  • 22,211
  • 11
  • 65
  • 85
  • 20
    `printf("%ld", ULONG_MAX)` outputs the value as -1. Should be `printf("%lu", ULONG_MAX)` for unsigned long as described by @Blorgbeard below. – jammus Nov 12 '11 at 16:03
  • 2
    Actually, you should change it to be `%ld`, to be more harmonic with OP question. – DrBeco Jun 21 '15 at 05:28
  • Yep Dr Beco; further, just `%l` triggers `warning: unknown conversion type character 0x20 in format [-Wformat]` – Patrizio Bertoni Jul 29 '15 at 10:53
205

I think you mean:

unsigned long n;
printf("%lu", n);   // unsigned long

or

long n;
printf("%ld", n);   // signed long
kiritsuku
  • 52,967
  • 18
  • 114
  • 136
Blorgbeard
  • 101,031
  • 48
  • 228
  • 272
96

On most platforms, long and int are the same size (32 bits). Still, it does have its own format specifier:

long n;
unsigned long un;
printf("%ld", n); // signed
printf("%lu", un); // unsigned

For 64 bits, you'd want a long long:

long long n;
unsigned long long un;
printf("%lld", n); // signed
printf("%llu", un); // unsigned

Oh, and of course, it's different in Windows:

printf("%l64d", n); // signed
printf("%l64u", un); // unsigned

Frequently, when I'm printing 64-bit values, I find it helpful to print them in hex (usually with numbers that big, they are pointers or bit fields).

unsigned long long n;
printf("0x%016llX", n); // "0x" followed by "0-padded", "16 char wide", "long long", "HEX with 0-9A-F"

will print:

0x00000000DEADBEEF

Btw, "long" doesn't mean that much anymore (on mainstream x64). "int" is the platform default int size, typically 32 bits. "long" is usually the same size. However, they have different portability semantics on older platforms (and modern embedded platforms!). "long long" is a 64-bit number and usually what people meant to use unless they really really knew what they were doing editing a piece of x-platform portable code. Even then, they probably would have used a macro instead to capture the semantic meaning of the type (eg uint64_t).

char c;       // 8 bits
short s;      // 16 bits
int i;        // 32 bits (on modern platforms)
long l;       // 32 bits
long long ll; // 64 bits 

Back in the day, "int" was 16 bits. You'd think it would now be 64 bits, but no, that would have caused insane portability issues. Of course, even this is a simplification of the arcane and history-rich truth. See wiki:Integer

Dave Dopson
  • 41,600
  • 19
  • 95
  • 85
  • 7
    Just to clarify: there are more architectures than x86 and x64, and on those architectures, char, short, int, long and long long have different meanings. For example, a 32 bit mcu with 16 bit memory alignment could use: char=short=int=16 bit; long=32 bits; long long = 64 bits – AndresR Sep 06 '16 at 19:19
  • 2
    @AndresR - absolutely, and it matters very deeply to people who do embedded programming (I built a kernel module for a smoke alarm once). Pity those poor souls when they try to use code that wasn't written for portability. – Dave Dopson Sep 07 '16 at 19:44
  • 2
    I'm not so sure that "most platforms have a `long` that's of size 32" is still true. E.g., I'm on Oracle Linux x86_64/amd64, and with `nvcc` a `long` is 8 bytes. – interestedparty333 Jun 17 '19 at 18:02
  • "Oh, and of course, it's different in Windows". Is there a cross-platform solution? – Aaron Franke May 13 '20 at 09:05
  • @interestedparty333 Yes, I'm >95% sure that in Linux `long` has the same size as the word/pointer size (so 32-bits on 32-bit Linux and 64-bits on 64-bit Linux). If you look inside the Linux kernel's code or inside Linux drivers, they usually store pointers in `long` or `unsigned long` variables. Actually, a few weeks ago a colleague of mine who ported some code from Windows to Linux had to go and change all our `long`s to `uint32_t` because we would constantly misuse them when developing under Windows. – adentinger Feb 19 '21 at 22:21
  • The statement "On most platforms, long and int are the same size (32 bits)" is simply untrue... most Unix and Unix-like systems use the LP64 model where ints are 32-bit and long is 64-bit - https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models – Nick Dowell Apr 19 '22 at 08:28
17

It depends, if you are referring to unsigned long the formatting character is "%lu". If you're referring to signed long the formatting character is "%ld".

krato
  • 1,226
  • 4
  • 14
  • 30
16

%ld see printf reference on cplusplus.com

kiritsuku
  • 52,967
  • 18
  • 114
  • 136
Rob Walker
  • 46,588
  • 15
  • 99
  • 136
13

I needed to print unsigned long long, so I found this works:

unsigned long long n;
printf("%llu", n);

For all other combinations, I believe you use the table from the printf manual, taking the row, then column label for whatever type you're trying to print (as I do with printf("%llu", n) above).

James Risner
  • 5,451
  • 11
  • 25
  • 47
Dolan Antenucci
  • 15,432
  • 17
  • 74
  • 100
-2

I think to answer this question definitively would require knowing the compiler name and version that you are using and the platform (CPU type, OS etc.) that it is compiling for.

Andrew O'Reilly
  • 1,645
  • 13
  • 15
  • 4
    Your answer should be a comment and not an answer by itself. – Jaime Hablutzel Aug 29 '19 at 05:01
  • No: there is no platform dependency on the correct format for printing a `long` — the correct answer is `%ld`. The range of values that may be printed does depend on the platform — on some platforms `long` will be a 32-bit type (especially back in 2008) and on other platforms it will be a 64-bit type (especially in 2022 and later). But if the data type is `long`, the correct `printf()` conversion specifier is `%ld` (though you can use `%li`). – Jonathan Leffler Nov 04 '22 at 21:00