Articles

Compiling a C Program: Behind the Scenes

From source code to binary. A step-by-step look at Preprocessing, Compilation, Assembly, and Linking.

Static Keyword

Private Globals, Persistent Locals. Master the logic of Memory Segments.

Volatile Keyword

Prevent Compiler Over-Optimization. Master the logic of Hardware-Software synchronization.

Extern Keyword

Cross-File Communication. Master the logic of External Linkage and Symbol Resolution.

Const Keyword

Read-Only ≠ Flash. Master the logic of Access Control and Memory Placement in Silicon.

The Inline Request

How inlining removes function call overhead by expanding code at the call site.

Inline: The Reality

The trade-off behind inlining: faster execution versus larger binaries.

Macros That Break Embedded Systems

When the preprocessor replaces logic before the compiler ever sees it. Powerful. Dangerous. Invisible to the debugger.

Why sizeof(pointer) ≠ sizeof(array)

Same data. Different meaning. One knows the memory. The other only knows the address.

Undefined Behavior: Silent Killers

The compiler assumes your program is correct. If it isn’t, the hardware may pay the price.

What Optimization Levels Actually Change

The same code. Different machine instructions. Different behavior under the debugger.

Why Debug Build Works but Release Build Fails

The same code. Different compiler decisions. Different behavior on hardware.

Linker Errors Every Embedded Engineer Must Understand

Compilation creates object files. The linker builds the final program. When symbols don’t match, the build breaks.

Function Pointers in Firmware: Callbacks Explained

Functions can be called directly. Or their addresses can be passed and invoked later. This is how firmware builds flexible systems.

Why main() Is Not the First Code That Runs

Your program starts before main(). Hardware resets. Startup code prepares the system.

Stack vs Heap: What Really Breaks First

Two memory regions. Different lifetimes. Different failure modes.

BSS vs DATA Section: Why Zero Matters

Two memory sections. Both store global variables. But only one starts from zero.

Memory Alignment: Invisible Performance Bug

The CPU reads memory in aligned chunks. Misaligned data slows execution. Sometimes it crashes the system.

Why Global Variables Are Dangerous in Firmware

Shared everywhere. Controlled nowhere. Easy to write, hard to trust.

Linker Script Basics: Flash vs RAM Placement

Firmware must fit into hardware memory. The linker decides where everything goes. Flash stores code. RAM runs the system.

Startup Code Explained: Reset to main()

The CPU resets. Execution begins at a fixed address. Startup code prepares the system before main() ever runs.

Why Large Local Variables Crash Systems

Allocated on the stack. Limited space. One large buffer can break everything.

How .map Files Help Debug Memory Issues

The build succeeds. The system still crashes. The answer is often in the .map file.

Memory-Mapped IO: How C Talks to Hardware

Hardware is not called. It is accessed. Through memory addresses.

Why Hardware Registers Must Be volatile

The hardware can change values. The compiler assumes it cannot. volatile forces reality back into the code.

Bit Manipulation Patterns Used in Drivers

Hardware speaks in bits. Drivers control them. One wrong bit changes everything.

Polling vs Interrupts: CPU Cost Explained

Either you keep asking… or hardware tells you. That choice costs CPU time.

Timers: Delay Loops vs Hardware Timers

One blocks the CPU. One lets hardware handle time.

ISR Rules That Prevent System Crashes

Interrupts don’t forgive mistakes. They run anytime. They must finish fast and leave a clean state.

Why You Should Never Call Delay in ISR

ISR runs at high priority. Delay holds the CPU at highest priority.