Question
I have trouble remembering how to print an unsigned long value in C using printf.
Suppose unsigned_foo is declared as an unsigned long. I tried several format strings:
printf("%lu\n", unsigned_foo);
printf("%du\n", unsigned_foo);
printf("%ud\n", unsigned_foo);
printf("%ll\n", unsigned_foo);
printf("%ld\n", unsigned_foo);
printf("%dl\n", unsigned_foo);
Instead of printing the expected unsigned value, some of these print a negative number. What is the correct way to print an unsigned long in C, and why do the other format specifiers behave incorrectly?
Short Answer
By the end of this page, you will know the correct printf format specifier for unsigned long in C, understand why mismatched format specifiers can print incorrect values, and learn how to choose the right specifier for related integer types.
Concept
In C, printf does not automatically know the type of each value you pass. It relies entirely on the format string to interpret the bytes correctly.
For an unsigned long, the correct format specifier is:
%lu
%starts a format specifierlmeanslongumeansunsigned decimal integer
So this is correct:
unsigned long unsigned_foo = 123456UL;
printf("%lu\n", unsigned_foo);
If you use the wrong specifier, printf interprets the argument as the wrong type. That causes undefined behavior, which often shows up as strange output such as negative numbers or garbage values.
For example:
%ldmeanslong int(signed long)%umeansunsigned int
Mental Model
Think of printf like a machine reading labeled boxes on a conveyor belt.
Each value you pass is a box containing bytes. The format string tells printf which label to use when opening each box.
If the box contains an unsigned long, the label must match:
unsigned→ useulong→ usel
So the correct label is %lu.
If you attach the wrong label, printf opens the box incorrectly. It may treat an unsigned value as signed, or expect a different size. That is why wrong format specifiers can print nonsense or negative values.
Syntax and Examples
Core syntax
printf("%lu\n", value);
Use %lu when value has type unsigned long.
Basic example
#include <stdio.h>
int main(void) {
unsigned long count = 4000000000UL;
printf("count = %lu\n", count);
return 0;
}
Output might be:
count = 4000000000
Why %ld is different
#include <stdio.h>
int main(void) {
unsigned long value = ;
(, value);
(, value);
;
}
Step by Step Execution
Consider this program:
#include <stdio.h>
int main(void) {
unsigned long value = 42UL;
printf("Value: %lu\n", value);
return 0;
}
Step by step
-
unsigned long value = 42UL;- A variable named
valueis created. - Its type is
unsigned long. - The suffix
ULmakes the literal anunsigned long.
- A variable named
-
printf("Value: %lu\n", value);printfreads the format string.- It sees ordinary text:
Value: - Then it sees
%lu %lumeans: read the next argument as an and print it in decimal form.
Real World Use Cases
Logging counters and totals
unsigned long request_count = 150000UL;
printf("Requests handled: %lu\n", request_count);
Printing file sizes or byte counts
unsigned long bytes = 2048UL;
printf("Downloaded: %lu bytes\n", bytes);
Reporting loop progress
unsigned long i;
for (i = 0; i < 3; i++) {
printf("Step %lu\n", i);
}
Debugging values from system or library code
Some APIs return values stored in larger integer types. When printing them for debugging, the format must match the actual type exactly.
Embedded and systems programming
In low-level C programs, exact integer sizes and signedness matter. Printing with the right specifier helps verify values correctly during testing and troubleshooting.
Real Codebase Usage
In real projects, developers usually do more than just write printf("%lu", x).
1. Print values with clear labels
printf("timeout_ms=%lu\n", timeout_ms);
This makes logs easier to read.
2. Use the exact matching specifier
Developers check the actual variable type before printing:
unsigned long total;
printf("%lu\n", total);
Not:
printf("%u\n", total); // wrong if total is unsigned long
3. Use warnings to catch mistakes
Compilers can detect many printf mismatches.
gcc -Wall -Wextra -Wformat program.c
These warnings are extremely helpful in real codebases.
4. Use <inttypes.h> for fixed-width integer types
If a codebase uses types like uint32_t or uint64_t, developers often prefer macros such as instead of guessing the right format string.
Common Mistakes
1. Using the right letters in the wrong order
This is wrong:
printf("%ul\n", value);
The correct order is length modifier first, then conversion specifier:
printf("%lu\n", value);
2. Using %d or %u for an unsigned long
Broken example:
unsigned long value = 5000000000UL;
printf("%u\n", value); // wrong
%u is for unsigned int, not unsigned long.
Use:
printf("%lu\n", value);
3. Using %ld because long looks close enough
Comparisons
| Type | Correct printf specifier | Meaning |
|---|---|---|
int | %d | signed decimal integer |
unsigned int | %u | unsigned decimal integer |
long | %ld | signed long decimal integer |
unsigned long | %lu | unsigned long decimal integer |
long long | %lld |
Cheat Sheet
// unsigned long
printf("%lu\n", value);
Quick rules
unsigned long→%lulong→%ldunsigned int→%uint→%dunsigned long long→%llulong long→%lld
Pattern
% + length modifier + type
Examples:
l= longll= long longd= signed decimalu= unsigned decimal
FAQ
What is the correct printf specifier for unsigned long in C?
Use:
%lu
Why does %ld sometimes print a negative number?
Because %ld tells printf to treat the value as a signed long. If the actual value is unsigned long, the types do not match.
Is %ul correct for unsigned long?
No. The correct order is %lu, not %ul.
Can I use %u for unsigned long if the value is small?
No. The format specifier must match the type, not just the value.
Why do some wrong format specifiers seem to work?
Sometimes the memory layout makes the output look correct by accident. But it is still undefined behavior and cannot be trusted.
How can I catch printf format mistakes?
Mini Project
Description
Build a small C program that prints several integer variables using printf. The purpose is to practice matching each variable type with the correct format specifier and to see how readable diagnostic output is written in real programs.
Goal
Create a program that correctly prints int, unsigned int, long, unsigned long, and unsigned long long values using the proper printf specifiers.
Requirements
- Declare at least five integer variables of different C integer types.
- Print each variable on its own line with a descriptive label.
- Use the correct
printfformat specifier for every variable. - Include at least one
unsigned longexample. - Compile cleanly with format warnings enabled.
Keep learning
Related questions
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.
C Pointer to Array vs Array of Pointers: How to Read Complex Declarations
Learn the difference between pointer-to-array and array-of-pointers in C, plus a simple rule for reading complex declarations correctly.