C: The Memory Model and Stack Frames

This is part two of two. Part one covers variables, symbolic constants, and the preprocessor. C always evaluates expressions before executing C evaluates every expression before running it. If main is missing, the linker signals an error, that’s the entry point contract. Parameters to main (argc, argv) behave like local variables. No garbage collector In C there’s no garbage collector. Local variables are not “objects” managed by a runtime; they’re temporary allocations on registers or the stack. When the function returns, they’re gone. There’s no tracing, no finalization, no safety net. This is by design. ...

March 28, 2026 · Giulia

C: Variables, Symbolic Constants, and the Preprocessor

This is part one of two. Part two covers the C memory model and stack frames. -Wall If I use the -Wall flag, the compiler emits warnings. Simple rule: always use it. 0 means more than zero The value 0 is equivalent to false in C boolean expressions. It also shows up in shell short-circuit evaluation. In an expression like ./a.out && ls, ls only executes if ./a.out returns 0. That’s because 0 is the success exit code, and && short-circuits on failure. So ./a.out returning 0 makes ls run. The 0 in the exit code sense is “success / true” from the shell’s perspective, opposite of the C boolean convention, which trips people up. ...

March 22, 2026 · Giulia

What Runs Before Your Program Does: The Dynamic Linker, PLT, and GOT

In the previous post, we saw that dynamically linked binaries don’t include library code, they just reference it. Which raises an obvious question: who actually loads that code at runtime, and how does the program find it? The answer is ld.so, the dynamic linker. And it runs before your main() does. The Bootstrap Problem When you execute a binary, the kernel reads its ELF header. One of the fields in that header (stored in the .interp section) contains a path like: ...

March 14, 2026 · Giulia

What Actually Happens When You Compile a C Program

Most developers treat compilation as a black box: you put source code in, you get a binary out. But there are actually three distinct stages happening, each with its own job and its own output. Understanding them has made me significantly better at debugging linker errors, understanding dependencies, and reasoning about what ends up in a binary. Let’s walk through what happens when you run gcc hello.c -o hello. Stage 1: The Preprocessor Before the compiler sees a single line of your code, the preprocessor runs. Its job is mechanical: it handles all the # directives. ...

March 8, 2026 · Giulia

Why You Shouldn't Wrap a Stream in a Transaction in Elixir

When you need to process a large number of records in Elixir, the instinct is often to wrap everything in a transaction. All-or-nothing semantics, right? Safe by default. Turns out, this is one of those cases where the “safe” choice creates a bigger problem than the one you were trying to avoid. Here’s what’s actually happening under the hood, and a better approach that’s both safer and more efficient. The Naive Approach Let’s say you have a batch job that needs to process thousands of files, calling an external API for each one and saving the result to the database. ...

March 1, 2026 · Giulia

Designing Extensible Action Pipelines in Elixir with Behaviours and Dynamic Dispatch

When you’re building a system that needs to execute many different “actions” (think AI-powered pipelines, data processing jobs, or any multi-step business logic) you quickly face a design question: how do you keep things extensible without coupling everything together? In Elixir, the answer often comes down to two powerful primitives: Behaviours and dynamic dispatch via atoms. Let me walk you through an architecture that elegantly solves this problem. The Problem: Many Actions, One Orchestrator Imagine you have an application that runs multiple independent actions, and that each one takes some input, does some processing, and produces a formatted output saved to a database. You could write each action as a standalone module with its own logic, but then whoever orchestrates them needs to know about every single one. That’s tight coupling, and it makes adding new actions painful. ...

February 21, 2026 · Giulia