Question
#include <stdio.h>
int main(void) {
unsigned long long int num = 285212672;
int normalInt = 5;
printf(
"My number is %d bytes wide and its value is %ul. A normal number is %d.\n",
sizeof(num),
num,
normalInt
);
return 0;
}
This program prints unexpected output:
My number is 8 bytes wide and its value is 285212672l. A normal number is 0.
I suspect the problem is the printf() format used for the unsigned long long int. What is the correct way to print an unsigned long long int with printf(), and why does the current format string produce incorrect output?
Short Answer
By the end of this page, you will understand how printf() format specifiers work in C, why the type and format must match exactly, and how to correctly print an unsigned long long int using %llu. You will also learn why sizeof() should usually be printed with %zu, and how format mismatches can cause strange output.
Concept
In C, printf() is a formatted output function. It does not know the types of the arguments by itself. Instead, it relies entirely on the format string to know how to interpret each value.
That means this is crucial:
%dexpects anint%uexpects anunsigned int%ldexpects along%lluexpects anunsigned long long
If the format specifier does not match the actual argument type, the behavior is undefined. In practice, this often leads to:
- wrong numbers being printed
- extra characters appearing
- later arguments being read incorrectly
- platform-dependent bugs
In your example, %ul is not the correct specifier for unsigned long long. In printf(), the length modifier must come before the conversion letter. So:
%lu=unsigned long- =
Mental Model
Think of printf() like a person reading labels on boxes coming down a conveyor belt.
Each format specifier is a label telling printf() what kind of box to open:
%d= "this box contains anint"%llu= "this box contains anunsigned long long"%zu= "this box contains asize_t"
If you put the wrong label on a box, printf() opens it the wrong way and gets confused. Once that happens, the rest of the boxes may also be read incorrectly.
So the rule is simple:
- the format string must describe the arguments exactly
- if the label is wrong, the output can become nonsense
Syntax and Examples
The correct syntax for printing an unsigned long long is:
printf("%llu", value);
Example:
#include <stdio.h>
int main(void) {
unsigned long long int num = 285212672;
printf("Value: %llu\n", num);
return 0;
}
Output:
Value: 285212672
If you also want to print the size of the variable:
#include <stdio.h>
int main(void) {
unsigned long long int num = 285212672;
printf("Size: %zu bytes, Value: %llu\n", (num), num);
;
}
Step by Step Execution
Consider this corrected example:
#include <stdio.h>
int main(void) {
unsigned long long num = 285212672;
int normalInt = 5;
printf("My number is %zu bytes wide and its value is %llu. A normal number is %d.\n",
sizeof(num), num, normalInt);
return 0;
}
Step by step
numis created as anunsigned long long.normalIntis created as anint.sizeof(num)is evaluated.- Its type is
size_t. - On many systems its value is
8.
- Its type is
printf()reads the format string from left to right.%zutellsprintf():
Real World Use Cases
Using the correct printf() format specifier matters anywhere C code prints values for debugging, logging, reporting, or user output.
Common real uses
- System programming: printing file sizes, memory sizes, counters, or IDs
- Embedded programming: printing hardware counters and timestamps
- Networking: logging packet counts or large sequence numbers
- Data processing tools: printing large unsigned totals
- Debugging: verifying variable values during development
Example: logging a large counter
unsigned long long totalRequests = 123456789ULL;
printf("Total requests: %llu\n", totalRequests);
Example: printing object size safely
char buffer[256];
printf("Buffer size: %zu\n", sizeof(buffer));
If the format is wrong, logs become unreliable, and debugging gets harder.
Real Codebase Usage
In real projects, developers usually follow a few practical patterns when using printf().
1. Match every type exactly
This is the most important habit.
size_t len = 42;
unsigned long long count = 1000;
printf("len=%zu count=%llu\n", len, count);
2. Let compiler warnings help you
Compiling with warnings catches many format mistakes.
gcc -Wall -Wextra -Wformat program.c
These warnings are extremely useful in production code.
3. Use fixed-width integer macros when needed
When code uses types like uint64_t, many codebases prefer <inttypes.h> macros for portability.
#include <inttypes.h>
#include <stdint.h>
uint64_t id = 123;
printf("id=%" PRIu64 "\n", id);
This is common in portable libraries and cross-platform systems code.
Common Mistakes
1. Using the wrong specifier order
Broken:
printf("%ul\n", num);
Correct:
printf("%lu\n", someUnsignedLong);
printf("%llu\n", num);
The length modifier comes before the final conversion letter.
2. Printing sizeof(...) with %d
Broken:
printf("%d\n", sizeof(num));
Better:
printf("%zu\n", sizeof(num));
sizeof returns size_t, not int.
3. Assuming wrong format strings are "close enough"
Broken:
n = ;
(, n);
Comparisons
| Type | Correct printf() specifier | Notes |
|---|---|---|
int | %d | Signed integer |
unsigned int | %u | Unsigned integer |
long | %ld | Signed long |
unsigned long | %lu | Unsigned long |
long long | %lld | Signed long long |
Cheat Sheet
// unsigned long long
unsigned long long x = 123ULL;
printf("%llu\n", x);
// long long
long long y = -123LL;
printf("%lld\n", y);
// unsigned long
unsigned long a = 10UL;
printf("%lu\n", a);
// size_t (for sizeof)
printf("%zu\n", sizeof(x));
Rules
printf()does not detect types automatically.- The format specifier must match the argument type exactly.
- For
unsigned long long, use%llu. - For
sizeof(...), use%zu. %ulis wrong;lis treated as a literal character.
Quick fixes for the original code
FAQ
What is the correct printf specifier for unsigned long long in C?
Use %llu.
Why does %ul print an extra l?
Because printf() reads %u as the conversion specifier and then treats l as a normal character.
Why did the next %d print the wrong value?
Because the previous format mismatch caused printf() to interpret the arguments incorrectly. This is undefined behavior.
Should I use %d for sizeof?
No. sizeof returns size_t, so %zu is the correct specifier.
What is the difference between %lu and %llu?
%lu is for . is for .
Mini Project
Description
Build a small C program that prints several integer types correctly. This project reinforces how printf() format specifiers must match the actual variable types, including int, unsigned int, unsigned long long, and size_t from sizeof.
Goal
Create a program that prints multiple numeric types using the correct printf() specifiers without warnings.
Requirements
- Declare an
int, anunsigned int, and anunsigned long long - Print each variable with the correct format specifier
- Print the size of at least one variable using
sizeof - Make sure the output is readable and labeled
- Use
main(void)and return0
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.