Skip to content

Declare vs Define

  • by

Declaration tells the compiler a name exists. Definition creates the actual thing the name refers to.

Mixing the two up leads to linker errors, runtime crashes, and hours of head-scratching. Master the distinction once and your code becomes clearer, faster to build, and safer to maintain.

🤖 This article was created with the assistance of AI and is intended for informational purposes only. While efforts are made to ensure accuracy, some details may be simplified or contain minor errors. Always verify key information from reliable sources.

Core Distinction in One Breath

A declaration is a promise; a definition is the delivery.

The compiler only needs the promise to compile a file. The linker needs the delivery to connect all files into a runnable program.

Keep this mental picture: declaration is the table of contents, definition is the full chapter.

Variables: The First Split

Declaration Without Definition

Prefixing extern before a variable creates a declaration.

Example: extern int counter; tells every file that includes this line, “Somewhere there is an int named counter; trust me.”

Definition in One File

Drop the extern and you get the definition: int counter = 0;.

Exactly one source file must contain this line so the linker finds one unique place in memory.

One-Definition Rule Safety

Put the extern line in a header, the plain definition in a single .cpp file.

Include the header everywhere you need the variable; the linker will merge references to the single definition.

Functions: Prototype vs Body

Prototype as Declaration

double area(double r); is a prototype.

It announces the function’s signature so other code can call it.

Body as Definition

The same line with braces becomes the definition: double area(double r){ return 3.14*r*r; }.

Only one definition may exist across the entire build; multiple prototypes are harmless.

Inline Exception

Marking a function inline allows its body in a header.

The compiler merges duplicate bodies into a single copy, so you can break the one-definition rule safely.

Classes and Structs: Special Rules

Forward Declaration

class Node; lets you declare pointers or references to Node before the full class is seen.

This speeds up compilation by reducing header churn.

Member Function Split

Declare methods inside the class body, define them in a .cpp file to hide implementation.

This keeps headers slim and rebuild times low.

Template Twist

Template functions and classes must be defined in every translation unit that uses them.

Put the full code in the header; the compiler generates specializations on demand.

Header Guards and Redundancy

Include-Once Pattern

Wrap headers in #ifndef HEADER_H / #define HEADER_H / #endif.

This prevents multiple declarations from causing redefinition errors.

Pragma Once Alternative

#pragma once is shorter and widely supported.

Either technique keeps declarations idempotent.

Storage Duration Illustrated

Static Variables

Declaration extern int shared; in a header pairs with definition int shared = 10; in one .cpp.

The single object lives for the whole program run.

Automatic Variables

Inside a function, int x = 5; is always a definition.

No extern is allowed here; storage is created each time the block runs.

Linkage and Visibility

Internal Linkage

Prefixing a variable with static at file scope makes it internal.

Each translation unit gets its own copy, invisible to others.

External Linkage

Omitting static gives external linkage, so the name can tie to a single definition elsewhere.

Use this to share globals across files cautiously.

Common Pitfalls

Multiple Definitions

Placing int value = 0; in a header included by two .cpp files triggers a linker error.

Remember: headers are pasted into every includer.

Missing Definition

Declaring extern int value; everywhere but forgetting to define it somewhere yields an unresolved symbol.

The linker cannot find the promised object.

Order Dependence

Calling a function before its prototype is seen makes the compiler assume old C rules, often breaking C++ type safety.

Always provide a declaration before use.

Best-Practice Cheat Sheet

For Globals

Header: extern int g_max;

Source: int g_max = 100;

For Functions

Header: void log(const std::string& msg);

Source: implement the body.

For Classes

Header: class declaration with inline tiny methods.

Source: definitions for large or non-template methods.

Quick Diagnostic Tips

Linker errors about “multiple definitions” almost always mean a variable definition landed in a header.

“Undefined reference” means you declared but never defined the entity.

When in doubt, add extern to the header and move the initializer to a single .cpp file.

Leave a Reply

Your email address will not be published. Required fields are marked *