UPI Study › Courses › C++ Programming › Free lessons › Lesson 8.4 Free with a free account
How the Compiler Manages Variable Storage
C++ Programming · Chapter 8: FunctionsSection 8.4 · lesson 54 of 84video coming soon
← Lifetime and ReachNext lesson: How Arguments Travel →
In this lesson
Behind the scenes of a function call.
- Tell a variable's lifetime from its visibility
- Predict automatic and static storage duration
- Describe a stack frame, on call and on return
- Explain stack overflow; tell const from constexpr
Transcript
Everything said in the video, section by section (1,487 words). Read along, or search it.
Opening Question
How Locals Appear and Vanish
A local variable appears when a function is called, and is gone when it returns. You've been relying on that for some time, without asking how it happens. The answer explains several things at once. Why a local starts fresh on every call, why some variables remember, why returning a reference to a local is a serious fault. And why a program can run out of room by calling itself too many times.
Key Distinction
Scope Versus Storage Duration
Two questions are easy to run together, and keeping them apart makes the rest of this lesson straightforward. Where can this name be used? That's scope, answered by where the declaration sits in the source. When does this storage exist? That's storage duration, answered by what kind of storage the compiler gave it. They usually move together, which is why they get confused. A local is visible inside its block, and exists for roughly as long. But they can separate. A static local is visible only inside one function, and yet exists for the whole run of the program. Once you've seen that case, the two ideas stay apart for good.
Worked Example
Automatic Locals Versus Static Locals
Parameters and ordinary local variables have automatic storage duration. It's the default, and needs no keyword. The storage is created when execution reaches the declaration, and released when the enclosing block ends. Nothing survives. So this counter doesn't count: three calls print 1, 1, 1. There's no single counter. There are three, one per call, each created, incremented, and destroyed. That's what you want almost all the time. Now writing static in front of the declaration changes its storage duration entirely. It's created once, before it's first used, and lives until the program ends. Its initialization runs only the first time. Three calls print 1, 2, 3. In both versions, the name is visible only inside the function. Only the lifetime differs.
Side Note
The Many Meanings of Static and Auto
A side note. The keyword auto once meant exactly this, automatic storage, and was so redundant nobody wrote it. Modern C++ reuses it for something entirely different: asking the compiler to work out a variable's type. Variables declared outside every function also have static storage duration. They exist from before main begins until after it ends. So static describes a lifetime, and several quite different declarations share it.
Comparison
Automatic and Static Storage Side by Side
Compare the two directly. Automatic storage is an ordinary local or parameter. It's created each time the declaration is reached, released when the block ends, and initialized every time. Static storage is created once, before first use, released when the program ends, and initialized only once. Later calls skip it. An uninitialized automatic variable holds whatever was in that memory, and reading it is undefined behavior. An uninitialized static one is set to zero. Automatic variables live in the function's stack frame. Static ones live in a fixed area set aside for the whole run. Use static locals sparingly. A static local makes a function remember, so the same arguments no longer guarantee the same result. Reach for it when the memory is the point, not to avoid passing a value in.
Shared Variables
Defining and Declaring with Extern
A program built from several source files sometimes needs one variable shared between them. It can be defined in only one place, where the storage is created. Here, totals dot cpp defines grand total. Every other file that wants to use it says so with extern. Report dot cpp declares it: no storage, just a reference to that one. That distinction is the whole idea. A definition creates the thing; a declaration only announces its name and type, so the compiler can check every use. Exactly one definition, any number of declarations. Built together, the program prints 12. Shared variables like this should be rare. Anything reachable from every file can be changed from every file, so a wrong value gives no clue where it came from. Pass values through parameters.
Keyword Notes
File-Level Static and the Retired Register
Two more keyword notes, so old code causes no confusion. The same word, static, does two unrelated jobs. Written on a local, it changes the lifetime. Written on a variable or function outside all functions, it doesn't change the lifetime, which is already static. It restricts the name to the file it appears in. And register. A processor keeps a small number of extremely fast storage locations of its own, called registers. The register keyword was once a hint that a variable should live in one. Compilers allocate registers by analyzing the whole function, and do it better than a programmer's intuition. The hint was routinely ignored, and it was removed from the language. Don't write it.
Mechanism
The Call Stack and Its Frames
Automatic variables have to live somewhere, and where they live explains their behavior completely. The mechanism is the call stack: a region of memory used strictly last in, first out, like a stack of plates where only the top one is reachable. Each time a function is called, a block of memory called a stack frame is pushed onto the top. When the function returns, its frame is popped off.
Definition
What a Stack Frame Holds
A frame holds the parameters, copied in at the call. The local variables. The return address, recording where in the caller to resume. And saved bookkeeping, whatever the machine must restore so the caller finds things as it left them. Everything that call needs, and nothing that outlives it.
Walkthrough
Frames Pushed and Popped in Calls
Watch the frames. Main runs, with its own frame. Main calls process, and process's frame is pushed on top. Process calls helper, and helper's frame goes on top. Only the top frame is active. When helper returns, its frame is popped, and its locals no longer exist. The return address is how control finds its way back down. Everything about automatic variables now follows. They're fresh on each call, because each call gets a new frame. They vanish on return, because the frame is popped. And two calls to the same function never interfere, because their frames are separate. That's also why a function can call itself without confusion.
Common Mistake
Why Returning a Local Reference Fails
Now it's clear why returning a reference to a local is fatal. Here, total lives in make total's frame. The frame is popped the moment the function returns. A reference handed back therefore refers to memory that's no longer in use, and will be reused by the very next call. The compiler warns, as shown. This is undefined behavior: it often produces a value that looks plausible for a while, and then doesn't. Return by value instead. It's the same rule you met with strings, and now you can see exactly why it holds.
Limits
Deep Recursion Exhausts the Stack
The stack isn't unlimited. A fixed region is set aside when the program starts, commonly around 1 to 8 megabytes, and every unreturned call occupies part of it. A function that calls itself pushes a new frame each time, and pops none until the innermost call returns. So depth is paid for in memory. A loop running 10 million times uses one frame. Recursion 1,000 deep is comfortable: it prints 1000. Recursion a million deep exhausts the stack, and the system stops the program. That's a stack overflow. Recursion with no stopping case fails within a fraction of a second.
Comparison
Endless Loop Versus Endless Recursion
Put the first and last cases side by side. An endless loop runs forever, consuming no extra memory. An endless recursion consumes memory on every pass, and is killed almost immediately. Knowing the difference tells you which mistake you've made, before you even open the code.
New Concept
Const Versus Constexpr Values
Some values are settled before the program ever runs, and saying so lets the compiler do the work. A plain int guarantees nothing. It may change later. A const int won't be modified after it's set, but its value may not be known until the program runs, because it might come from input. A constexpr int won't be modified, and its value must be computable during compilation. The compiler rejects anything it can't work out then, as shown. So a constexpr value can be used wherever the language demands a known figure, like the size of a fixed array. Use const to say a value must not change, and constexpr when it must also be known before the program starts.
Quick Check
Moving the Counter Outside the Function
Quick check. Take the plain tick, and move its int calls = 0 declaration outside every function, above them all. What do three calls to tick print now? Pause and predict. 1, 2, 3. A variable outside every function has static storage duration: one counter, created once, for the whole run. What changed, compared with a static local, is scope. Any function below it in the file can now see it, and change it.
Key Takeaways
Scope, Duration, Frames, and Constexpr Recap
To summarize. Scope is where a name can be used. Storage duration is how long its storage exists. Ordinary locals are automatic: fresh on every call, and gone on return. Static locals remember, at a cost in predictability. Each call pushes a stack frame, and each return pops it, which is why deep recursion can run out of room. And constexpr means a value is also known before the program runs.
About C++ Programming at UPI Study
C++ Programming (Computer Science 242) is a self-paced online course of 84 video lessons in 11 chapters, from your first program to decisions, loops, arrays, functions, classes, files, pointers and inheritance. It carries a NCCRS credit recommendation for 3 semester credits.
Every lesson transcript is free on pages like this one, and the videos are free with a free UPI Study account. Enrolling adds a practice quiz after each lesson, the graded work and final exam that earn the credit, lifetime access, and an official transcript on completion. UPI Study has helped over 130,000 students with college credits. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Enroll now → Course details Download the syllabus Every course with PRO →
Why take it here
Why students take C++ Programming with UPI Study
Where the credit goes
Universities that work with NCCRS
C++ Programming carries a NCCRS credit recommendation. These universities work with NCCRS; some are UPI Study's signed partners. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Thomas Edison State UniversitySigned partner
University of the PeopleSigned partner
Charter Oak State CollegeSigned partner
Strayer UniversitySigned partner
Columbia Southern UniversitySigned partner
Indiana TechSigned partner
Penn StateWorks with NCCRS
Southern New Hampshire UniversityWorks with NCCRS
SUNYWorks with NCCRS
+many more cooperating universitiesFind my college →Find my college → Not listed? Ask Athena in the corner of this page, or book a 15-minute call.
FAQ
Questions students ask us
About How the Compiler Manages Variable Storage
What is the difference between scope and lifetime of a variable in C++?
What does static do to a local variable in C++?
What happens on the call stack when a function is called and when it returns?
What is the difference between const and constexpr in C++, and what causes a stack overflow?
About the C++ Programming course
How many college credits is C++ Programming?
How much does C++ Programming cost and what is included?
Which universities accept UPI Study credits?
How long does C++ Programming take?
How are the exams done?
How do my credits reach my college?
Ready for the full course? Earn 3 credits in C++ Programming.
84 video lessons, a quiz after each one, and the graded work that earns the credit. Recommended for credit by NCCRS.
3 credits · NCCRSEnroll →