placeholder for a value (% introducer + d specifier character)
escape sequence
\n
C language / syntax
special character encoded as backslash sequence
Precise usage:"blabla1 %d\n" is a string literal that is used as a format string by printf.
In everyday usage both terms are used interchangeably for the whole quoted string — that is sloppy but universally understood.
Conversion Specifiers
Specifier
Type
Example output
%d / %i
Signed decimal int
-42
%u
Unsigned decimal int
42
%o
Unsigned octal
10
%x / %X
Unsigned hex lower/upper
ff / FF
%f
Decimal float
3.140000
%e / %E
Scientific notation
3.140000e+00
%g / %G
Shorter of %f / %e
3.14
%c
Character
A
%s
String
hello
%p
Pointer address
0x7ffd...
%%
Literal %
%
Length Modifiers
Modifier
Type
hh
char / unsigned char
h
short / unsigned short
l
long / unsigned long
ll
long long / unsigned long long
z
size_t / ssize_t
t
ptrdiff_t
j
intmax_t / uintmax_t
Flags
Flag
Meaning
Example
-
Left-align
"%-10s"
+
Always show sign
"%+d" → +42
0
Zero-pad
"%05d" → 00042
#
Alternate form
"%#x" → 0xff
String Literal Storage
Declaration
Section
Note
printf("hello")
.rodata
no variable, read-only
const char *s = "hello"
.rodata
pointer on stack, string in .rodata
char s[] = "hello"
.rodata + stack
.rodata holds original, stack holds copy
static char s[] = "hello"
.rodata + .data
.rodata holds original, .data holds copy
Writing to a string literal is undefined behavior:
char*s="hello";
s[0] ='H'; // UB — segfault, .rodata is read-onlychars[] ="hello";
s[0] ='H'; // OK — copy on stack, writable
Memory Sections — Full Picture
What
Section
Note
String literals "hello"
.rodata
read-only, shared across all uses
Integer/float literals 42, 3.14, 'A'
.text
embedded as immediate in instruction encoding
Global / static, uninitialized
.bss
zeroed by loader, not stored in binary
Global / static, initialized to 0
.bss
compiler treats same as uninitialized
Global / static, initialized non-zero
.data
stored in binary
Local variable
stack
not zeroed — garbage unless explicitly set
malloc / heap
heap
always explicit, never holds literals
Why .bss Exists
.bss does not store actual bytes in the binary — only a size. The OS/loader zeroes the memory at startup. This keeps the binary small even when you have large zero-initialized buffers.
size a.out
# text data bss dec# 1234 56 128 1418
Zero-Initialization Rule (C11 §6.7.9)
All variables with static storage duration are zero-initialized by the C standard — even without explicit = 0.
When wrapping printf in a custom logger, annotate with __attribute__((format)) so the compiler type-checks the format string against variadic args:
staticinlinevoidlog_msg(constchar*file, intline, constchar*fmt, ...)
__attribute__((format(printf, 3, 4)));
// ^ ^// | +-- index of first variadic argument// +----- index of fmt (format string) argument
This catches mismatches like log_msg(__FILE__, __LINE__, "%d", "string") at compile time.