Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
Storage Class Examples: nm, size, const Tables, static Buffers and the Start-up Model
Nine worked examples with real tool output: classify variables with nm, measure flash and SRAM with size, compare const tables, big local versus static arrays, register, and the reset copy/clear model. Study this one of the storage class examples carefully.
Storage Class Examples: What This Page Covers
These storage class examples use the real tools, nm, size, GCC diagnostics and running programs, to show where each variable lives and how long it lasts. Section letters and sizes come from a PC build; the classification rules are identical on the STM32F407. This of the storage class examples is the one interviewers love.
| # | Example | Skill |
|---|---|---|
| 1 | Classify every variable with nm | Section placement |
| 2 | How const changes the section | Flash vs SRAM |
| 3 | Cost of a big table: const or not (size) | Memory budgeting |
| 4 | A big local array versus a static one | Stack vs .bss |
| 5 | Stack versus static addresses | Where objects sit relative to each other |
| 6 | The register keyword and its one hard rule | register |
| 7 | Zero cost of .bss: size of a 4000-byte array | data vs bss |
| 8 | Start-up model: what happens to .data and .bss | Reset sequence |
| 9 | extern + static: a small module with hidden state | Encapsulation |
| 10 | Mini exercises | Self-test |
Example 1: Classify Every Variable With nm
Problem: For each of the variables A to I predict the section, then check the real symbol table. The storage class examples on this page use real tool output.
| Var | Your prediction | Reason |
|---|---|---|
A counter | .bss | global, no initializer |
B limit | .data | global, non-zero initializer |
C mode | .bss | file static, zero |
D retries | .data | file static, non-zero |
E MAX_USERS | .rodata | const global |
F banner | .rodata | const array |
G calls | .bss | static local, zero |
H last | .data | static local, -1 is non-zero |
I tmp | stack/register | auto: no symbol |
Every prediction matches. Notice that tmp has no symbol: automatic variables never appear in the object file’s symbol table. An initializer of -1 forces .data even though the variable is static. Keep these storage class examples in mind when reading a map file.
Example 2: How const Changes the Section
Problem: The same four numbers are stored three ways. Which version uses SRAM?
table_ram is in .data: 16 bytes in flash for the initial image and 16 bytes of SRAM. table_flash is in .rodata: 16 bytes of flash and no SRAM. Now the same table as a const local:
const local array gets no symbol of its own: the compiler builds it on the stack at run time (or keeps the constants in code). At higher optimization levels it may place an anonymous read-only copy in .rodata, but you cannot rely on that. To guarantee flash, write static const at file scope or inside the function.Example 3: The Cost of a Big Table With and Without const
Problem: A 256-entry table of 16-bit values is added to the firmware. How much flash and SRAM does it use in each form?
| Declaration | Section | Flash | SRAM |
|---|---|---|---|
unsigned short t[256] = {...}; | .data | 512 B | 512 B |
const unsigned short t[256] = {...}; | .rodata | 512 B | 0 B |
Without const the 512 bytes appear in the data column (text = 32 is just the small function that uses them); with const they move into text (544 = 32 + 512) and data drops to 0. Only the second form leaves SRAM free. On the STM32F407 the arithmetic is the same: 512 B of the 128 KB is 0.4 %, but a few dozen such tables (waveforms, CRC tables, font bitmaps, calibration curves) quickly add up.
Example 4: A Big Local Array Versus a Static One
Problem: Two functions compute the same sum. What differs in memory?
| Version | Where the 4096 bytes are | When they are reserved | Risk on 128 KB SRAM |
|---|---|---|---|
sum_stack | Stack | On every call | Stack overflow if the stack is small; invisible to the linker |
sum_static | .bss | Always (fixed at link time) | Linker reports if RAM overflows; not re-entrant |
The output is identical; the difference is who notices a problem and when. A static buffer fails at link time with a clear message. A stack buffer fails at run time, possibly in the field, with a hard fault or silent corruption.
Example 5: Static Objects Versus the Stack, by Address
Problem: Where do globals, statics, constants and the heap sit relative to a stack variable? Absolute addresses vary by system, so the program prints only the relationships.
On a PC with address-space randomisation the exact numbers change on every run, but static objects typically sit far below the stack. On an STM32F407 the layout is stricter: .data and .bss start at 0x20000000, the heap follows them, and the stack starts at the top of SRAM (0x20020000) and grows toward the heap.
Example 6: The register Keyword and Its One Hard Rule
Problem: Is register ever useful, and what does the compiler enforce?
Taking the address is an error
The program works with or without the keyword, because the compiler places total and i in registers anyway. The only observable effect of register is the error above. Remove it from your own code and let the optimizer decide.
Example 7: The Zero Cost of .bss in Flash
Problem: Compare two 4000-byte arrays: one uninitialized, one filled with a non-zero pattern. What do they cost?
| Array | Section | Flash used | SRAM used |
|---|---|---|---|
zeros | .bss | 0 | 4000 |
ones | .data | 4000 (the image) | 4000 |
= {1} for a single non-zero element turns the whole 4000-byte array into .data, because the other bytes must be zero in the flash image too (unless the toolchain compresses it). Initialize such buffers at run time instead.Example 8: Start-up Model, Watching .data and .bss Get Their Values
Problem: Show the three states of two initialized and two uninitialized variables around reset: garbage, after the .data copy, and after the .bss clear.
Hexadecimal EEEEEEEE stands for what a real SRAM contains after power-up: unpredictable. If your own start-up file skipped the first loop, baud would stay garbage and the UART would never run at 115200.
Example 9: A Small Module Combining All the Storage Classes
Problem: Build a moving-average sensor module whose state is hidden, whose limit is read-only and shared, and whose helper variables use the least possible scope.
| Item | Storage class | Section | Visibility |
|---|---|---|---|
g_sensor_limit | external, const | .rodata (flash) | all files via extern |
s_window[4] | static (internal) | .bss (SRAM) | sensor.c only |
s_index | static (internal) | .bss (SRAM) | sensor.c only |
sum, i | auto | register/stack | inside sensor_average() |
Only two small functions are exported. The 9000 reading was clamped to 4095 before it entered the window, so the average of 300, 400, 4095 and 500 is 1323 (integer division). The same file compiles unchanged for the STM32F407.
Example 10: Mini Exercises
Exercise 1: In which section is static int n = 0; at file scope?
.bss. An explicit zero initializer is still zero, so no flash image is needed.Exercise 2: How many bytes of SRAM does const uint8_t tab[100] = {...}; (file scope) use?
.rodata (flash).Exercise 3: uint32_t buf[256]; inside a function, called from a task with a 512-byte stack. What happens?
static or a larger stack.Exercise 4: Flash used and static SRAM used for text=2000, data=300, bss=700?
Exercise 5: Is extern int x; in .data or .bss?
Exercise 6: Why is register int x; &x an error?
Exercise 7: Which section holds the string literal in printf("hi")?
.rodata (flash).Key Takeaways from the Storage Class Examples
- These storage class examples show that
nmclassifies variables exactly as the language rules predict. - Non-zero initializer →
.data(flash + SRAM); zero or none →.bss(SRAM only);constglobal →.rodata(flash only). conston a local does not move it to flash; usestatic const.- A big stack array fails at run time; a static one is counted by the linker.
registerchanges nothing except forbidding&.- Start-up code turns the flash image into valid .data and clears .bss before
main(). - Hide module state with
staticand export only functions and read-only constants.
Ready for the quiz?
Next: match variables to sections, MCQs, code challenges and interview questions on storage classes.
Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments