C++98corebeginner
Storage Class Specifiers
C++98 · The Foundation · Compiler flag: -std=c++98
Explanation
Keywords (`static`, `extern`, `register`) that control the storage duration, linkage, and lifetime of variables.
Real-World Scenario
Use `static` to count how many times a function has been called across a program.
Quick Snippet
snippet.cpp
void counter() { static int count = 0; count++; }Full Example
storage_class.cpp
// CodeNebula - C++98 Example: Storage Classes
// Compile: g++ -std=c++98 -Wall -Wextra -o example storage_class.cpp
// Storage classes control the lifetime, visibility, and linkage of variables:
// - auto : (default) local scope, automatic lifetime
// - static : persists across function calls / limits linkage
// - extern : declares a variable defined elsewhere
// - register : hints at register storage (compiler may ignore)
// - mutable : (covered separately in mutable.cpp)
//
// This example focuses on static (local, global, and class member) and extern.
#include <iostream>
#include <string>
// ------------------------------------------------------------------
// 1. static local variable: retains value between function calls
// ------------------------------------------------------------------
int callCounter() {
static int count = 0; // Initialized only once, persists across calls
++count;
return count;
}
// ------------------------------------------------------------------
// 2. static local for one-time initialization
// ------------------------------------------------------------------
const std::string& getConfig() {
// This string is created only on the first call
static std::string config = "DefaultConfig_v1";
return config;
}
// ------------------------------------------------------------------
// 3. static global variable: internal linkage (file scope only)
// Cannot be accessed from other translation units.
// ------------------------------------------------------------------
static int fileLocalVar = 42;
static void fileLocalFunction() {
std::cout << " fileLocalFunction: fileLocalVar = " << fileLocalVar << std::endl;
}
// ------------------------------------------------------------------
// 4. extern variable: defined in this file, could be accessed from
// another translation unit via 'extern int sharedVar;'
// ------------------------------------------------------------------
int sharedVar = 999; // Definition (extern by default for global vars)
// In another .cpp file, you would write:
// extern int sharedVar; // Declaration only, uses the one defined above
// ------------------------------------------------------------------
// 5. static class members: shared across all instances
// ------------------------------------------------------------------
class Player {
private:
std::string name;
int score;
static int totalPlayers; // Shared counter
static int totalScore; // Shared score accumulator
public:
Player(const std::string& n, int s) : name(n), score(s) {
++totalPlayers;
totalScore += s;
}
~Player() {
--totalPlayers;
totalScore -= score;
}
void print() const {
std::cout << " " << name << " (score: " << score << ")" << std::endl;
}
// Static member functions: can be called without an instance
static int getTotalPlayers() { return totalPlayers; }
static int getTotalScore() { return totalScore; }
static double getAverageScore() {
if (totalPlayers == 0) return 0.0;
return static_cast<double>(totalScore) / totalPlayers;
}
static void printStats() {
std::cout << " Total players: " << totalPlayers
<< ", Total score: " << totalScore
<< ", Average: " << getAverageScore() << std::endl;
}
};
// Static member definitions (must be outside the class in C++98)
int Player::totalPlayers = 0;
int Player::totalScore = 0;
// ------------------------------------------------------------------
// 6. static in a class: constant (integral types only in C++98)
// ------------------------------------------------------------------
class Config {
public:
static const int MAX_CONNECTIONS = 100; // OK in C++98 for integral const
static const int TIMEOUT = 30;
// Non-integral static const must be defined outside
static const double PI;
};
// Definition for non-integral static const
const double Config::PI = 3.14159265;
// ------------------------------------------------------------------
// 7. register keyword: a hint to the compiler
// ------------------------------------------------------------------
int sumWithRegister(int n) {
register int sum = 0; // Hint: keep 'sum' in a CPU register
register int i; // Hint: keep 'i' in a register
for (i = 1; i <= n; ++i) {
sum += i;
}
return sum;
// Note: Modern compilers ignore 'register' and optimize automatically.
}
// ------------------------------------------------------------------
// 8. Demonstrating static local in a recursive context
// ------------------------------------------------------------------
void recursiveCounter(int depth) {
static int callCount = 0;
++callCount;
std::cout << " depth=" << depth << ", total calls so far=" << callCount << std::endl;
if (depth > 0) {
recursiveCounter(depth - 1);
}
}
int main() {
std::cout << "=== C++98 Storage Classes ===" << std::endl;
// --- 1. static local variable ---
std::cout << "\n--- 1. Static local variable ---" << std::endl;
for (int i = 0; i < 5; ++i) {
std::cout << " callCounter() = " << callCounter() << std::endl;
}
// Expected: 1, 2, 3, 4, 5 (persists across calls)
// --- 2. static local for lazy initialization ---
std::cout << "\n--- 2. Static local (lazy init) ---" << std::endl;
std::cout << " Config: " << getConfig() << std::endl;
std::cout << " Config: " << getConfig() << std::endl;
// Expected: Same string both times, initialized only once
// --- 3. static global (file scope) ---
std::cout << "\n--- 3. Static global (file scope) ---" << std::endl;
fileLocalFunction();
// Expected: fileLocalVar = 42
std::cout << " fileLocalVar cannot be accessed from other .cpp files" << std::endl;
// --- 4. extern ---
std::cout << "\n--- 4. extern variable ---" << std::endl;
std::cout << " sharedVar = " << sharedVar << std::endl;
// Expected: 999
std::cout << " Other files can use: extern int sharedVar;" << std::endl;
// --- 5. static class members ---
std::cout << "\n--- 5. Static class members ---" << std::endl;
std::cout << "Before creating players:" << std::endl;
Player::printStats();
// Expected: Total players: 0, Total score: 0, Average: 0
Player p1("Alice", 100);
Player p2("Bob", 85);
Player p3("Charlie", 92);
p1.print();
p2.print();
p3.print();
std::cout << "After creating 3 players:" << std::endl;
Player::printStats();
// Expected: Total players: 3, Total score: 277, Average: 92.3333
{
Player p4("Diana", 110);
std::cout << "After adding Diana:" << std::endl;
Player::printStats();
// Expected: Total players: 4, Total score: 387
}
// p4 destroyed here
std::cout << "After Diana goes out of scope:" << std::endl;
Player::printStats();
// Expected: Total players: 3, Total score: 277
// Accessing static members through class name
std::cout << "\nAccess via class name: Player::getTotalPlayers() = "
<< Player::getTotalPlayers() << std::endl;
// --- 6. static const class members ---
std::cout << "\n--- 6. Static const members ---" << std::endl;
std::cout << " Config::MAX_CONNECTIONS = " << Config::MAX_CONNECTIONS << std::endl;
std::cout << " Config::TIMEOUT = " << Config::TIMEOUT << std::endl;
std::cout << " Config::PI = " << Config::PI << std::endl;
// Expected: 100, 30, 3.14159
// --- 7. register keyword ---
std::cout << "\n--- 7. register keyword ---" << std::endl;
std::cout << " sum(100) = " << sumWithRegister(100) << std::endl;
// Expected: 5050
std::cout << " (register is just a hint, compiler may ignore it)" << std::endl;
// --- 8. static in recursive context ---
std::cout << "\n--- 8. Static in recursion ---" << std::endl;
recursiveCounter(3);
// Expected: depth=3 calls=1, depth=2 calls=2, depth=1 calls=3, depth=0 calls=4
return 0;
}
/*
Expected Output:
=== C++98 Storage Classes ===
--- 1. Static local variable ---
callCounter() = 1
callCounter() = 2
callCounter() = 3
callCounter() = 4
callCounter() = 5
--- 2. Static local (lazy init) ---
Config: DefaultConfig_v1
Config: DefaultConfig_v1
--- 3. Static global (file scope) ---
fileLocalFunction: fileLocalVar = 42
fileLocalVar cannot be accessed from other .cpp files
--- 4. extern variable ---
sharedVar = 999
Other files can use: extern int sharedVar;
--- 5. Static class members ---
Before creating players:
Total players: 0, Total score: 0, Average: 0
Alice (score: 100)
Bob (score: 85)
Charlie (score: 92)
After creating 3 players:
Total players: 3, Total score: 277, Average: 92.3333
After adding Diana:
Total players: 4, Total score: 387, Average: 96.75
After Diana goes out of scope:
Total players: 3, Total score: 277, Average: 92.3333
Access via class name: Player::getTotalPlayers() = 3
--- 6. Static const members ---
Config::MAX_CONNECTIONS = 100
Config::TIMEOUT = 30
Config::PI = 3.14159
--- 7. register keyword ---
sum(100) = 5050
(register is just a hint, compiler may ignore it)
--- 8. Static in recursion ---
depth=3, total calls so far=1
depth=2, total calls so far=2
depth=1, total calls so far=3
depth=0, total calls so far=4
*/
Run command
g++ -std=c++98 -Wall -Wextra -o example storage_class.cpp