Question

Definition vs Declaration in C and C++: What’s the Difference?

ccppdeclarationterminologyc++-faq

Question

In C and C++, what is the difference between a declaration and a definition? The meaning of these two terms is confusing to me, and I want to understand how they differ in practice.

Short Answer

By the end of this page, you will understand what declarations and definitions mean in C and C++, how they relate to variables, functions, and types, and why the distinction matters when organizing code across multiple files.

Concept

A declaration tells the compiler that a name exists and describes its type.

A definition actually creates that thing or provides its full implementation.

In simple terms:

  • A declaration says: "This exists somewhere. Here is what it looks like."
  • A definition says: "Here it is. This is the real thing."

Why this matters

In real programs, code is usually split across multiple files:

  • header files (.h, .hpp) often contain declarations
  • source files (.c, .cpp) often contain definitions

This lets many files know about the same variable or function without creating duplicates.

Variables

A variable declaration can introduce a variable without allocating storage, usually with extern:

extern int count;

This tells the compiler:

  • there is an int called count
  • it is defined somewhere else
  • do not create storage for it here

A variable definition creates the variable:

int count = 0;

This allocates storage for count.

Functions

A function declaration gives the function's name, return type, and parameters:

int add(int a, int b);

This tells the compiler how the function can be called.

A function definition includes the body:

int add(int a, int b) {
    return a + b;
}

This is the actual implementation.

Important rule

Every definition is also a declaration, but not every declaration is a definition.

That is the key idea.

Types

For some types, the line can be only a declaration or both a declaration and a definition.

For example:

struct User;

This is a declaration of a struct type.

But this is a definition:

struct User {
    int id;
    char name[50];
};

Now the compiler knows the full layout of the type.

Mental Model

Think of a declaration like a table of contents entry in a book.

It tells you:

  • the name of something
  • what kind of thing it is
  • where you can expect to use it

But it does not give the full content.

A definition is the actual chapter.

It contains the real material.

Analogy

Imagine a movie cast list:

  • Declaration: "A character named Alex exists in this story."
  • Definition: "Here is Alex, with dialogue, scenes, and actions."

The compiler needs declarations so it can understand references to names. The linker needs exactly the right set of definitions so the program can be built successfully.

Take Quiz

Syntax and Examples

Core syntax

Variable declaration

extern int total;

Variable definition

int total = 10;

Function declaration

double multiply(double x, double y);

Function definition

double multiply(double x, double y) {
    return x * y;
}

Type declaration

struct Item;

Type definition

struct Item {
    int id;
    double price;
};

Beginner-friendly example

math_utils.h

int square(int n);
extern int globalValue;

math_utils.cpp

#include "math_utils.h"

int globalValue = 5;

int square(int n) {
    return n * n;
}

main.cpp

#include <iostream>
#include "math_utils.h"

int main() {
    std::cout << square(4) << "\n";
    std::cout << globalValue << "\n";
}

Explanation

  • int square(int n); is a declaration in the header.
  • int square(int n) { ... } is the definition in the source file.
  • extern int globalValue; declares a variable without creating it.
  • int globalValue = 5; defines the variable once.

This pattern is common in C and C++ projects.

Step by Step Execution

Consider this example:

#include <iostream>

int greet();      // declaration

int main() {
    std::cout << greet() << "\n";
}

int greet() {     // definition
    return 42;
}

Step by step

  1. The compiler reads int greet();

    • It learns that a function named greet exists.
    • It knows greet takes no arguments and returns int.
  2. The compiler reads main().

    • Inside main, it sees greet() being called.
    • This is allowed because the function was already declared.
  3. Later, the compiler reads:

    int greet() {
        return 42;
    }
    
    • Now it sees the actual implementation.
    • This is the definition.
  4. During linking, the program connects the call to greet() with its definition.

What if the declaration was missing?

Then the compiler would not know what greet() is at the point where main calls it. In C++, that causes an error.

What if the definition was missing?

The compiler might accept the declaration, but the linker would fail because the actual function implementation does not exist.

Real World Use Cases

1. Header and source file organization

Large C and C++ programs usually place declarations in headers and definitions in source files.

Example:

  • database.h declares connect()
  • database.cpp defines connect()

2. Sharing global configuration

A project may need one shared global variable:

// config.h
extern int maxConnections;
// config.cpp
int maxConnections = 100;

This avoids creating multiple copies.

3. Library development

Libraries expose declarations in public headers so other programs know how to call functions. The real code is provided by compiled object files or libraries.

4. Forward declarations to reduce dependencies

Sometimes developers declare a type before its full definition to avoid including heavy headers:

struct Engine;

This can speed up compilation and reduce coupling between files.

Take Quiz

Real Codebase Usage

In real codebases, declarations and definitions are used as part of project structure and build organization.

Common patterns

Public interface in headers

Headers describe what is available:

// logger.h
void logMessage(const char* message);

Implementation in source files

Source files provide the real code:

// logger.cpp
#include <iostream>

void logMessage(const char* message) {
    std::cout << message << "\n";
}

Shared globals with extern

Teams usually avoid globals when possible, but when they are used, the safe pattern is:

  • declare in a header with extern
  • define once in a source file

Forward declarations

Developers often forward-declare classes or structs when only a pointer or reference is needed:

class Database;

class Service {
public:
    void setDatabase(Database* db);
};

This avoids unnecessary includes.

Error prevention through separation

Keeping declarations in headers and definitions in source files helps:

  • avoid duplicate definitions
  • expose only the interface
  • keep implementation details private
  • make code easier to maintain

Common Mistakes

1. Defining a global variable in a header

Broken example:

// settings.h
int timeout = 30;

If multiple source files include this header, each one gets its own definition, which usually causes linker errors.

Better

// settings.h
extern int timeout;
// settings.cpp
int timeout = 30;

2. Declaring a function but never defining it

Broken example:

int calculateTotal(int a, int b);

int main() {
    return calculateTotal(2, 3);
}

If no definition exists, linking fails.

3. Confusing forward declaration with full type definition

Broken example:

struct User;

int main() {
    User u; // error: compiler does not know the size of User
}

A forward declaration only says the type exists. It does not provide the layout.

Better

struct User {
    int id;
};

int main() {
    User u;
}

4. Thinking every declaration creates storage

This is false:

extern int score;

This does not create the variable. It only refers to one defined elsewhere.

5. Multiple function definitions

Broken example:

int add(int a, int b) {
    return a + b;
}

int add(int a, int b) {
    return a + b;
}

A function should usually have one definition with a given signature in a program.

Comparisons

ConceptDeclarationDefinition
PurposeIntroduces a name and typeCreates the object or provides full implementation
Variable exampleextern int x;int x = 5;
Function exampleint f();int f() { return 1; }
Allocates storage?Usually noYes, for objects
Contains function body?NoYes
Can appear multiple times?Usually yes, if consistentUsually only once per program

Declaration vs forward declaration

A forward declaration is a specific kind of declaration that introduces something before its full definition appears.

Example:

class Widget;

This is useful when the compiler only needs to know that Widget exists.

Declaration vs initialization

These are different ideas.

int x = 10;

This line is:

  • a declaration
  • a definition
  • and an initialization

Initialization means giving an initial value. Definition means creating the variable.

Take Quiz

Cheat Sheet

Quick rules

  • A declaration introduces a name and type.
  • A definition provides the actual object, function body, or full type.
  • Every definition is a declaration.
  • Not every declaration is a definition.

Common examples

extern int x;          // declaration only
int x = 3;             // definition

int add(int a, int b); // declaration
int add(int a, int b) { return a + b; } // definition

struct Node;           // declaration
struct Node { int v; };// definition

Header/source pattern

// file.h
int work();
extern int counter;

// file.cpp
int counter = 0;
int work() {
    return counter;
}

Remember

  • Use extern for variable declarations in headers.
  • Put variable definitions in exactly one source file.
  • Put function declarations in headers when shared.
  • Put function definitions in source files unless there is a good reason not to.
  • A forward-declared type cannot be used to create objects until fully defined.

FAQ

Is a definition also a declaration?

Yes. A definition introduces the name, so it is also a declaration.

Why do header files usually contain declarations instead of definitions?

Because headers are included in many source files. Putting definitions there can create duplicate definitions.

What does extern mean for a variable?

It tells the compiler that the variable exists somewhere else and should not be created here.

Can a function be declared many times?

Yes, as long as the declarations are consistent. But it should normally be defined only once.

What is a forward declaration?

It is a declaration that introduces a type or function before the full definition is seen.

Why do I get a linker error even though I declared the function?

Because a declaration is not enough. The linker also needs the actual definition.

Can I create an object from a forward-declared struct or class?

No. The compiler needs the full definition to know its size and layout.

Take Quiz

Mini Project

Description

Create a small multi-file C++ program that shares a function and a global variable across files. This demonstrates how declarations go in a header and definitions go in a source file.

Goal

Build a program that declares a function and a global variable in a header, defines them in a source file, and uses them from main.

Requirements

  1. Create a header file that declares one function and one global variable using extern.
  2. Create a source file that defines the function and the global variable.
  3. Create a main file that includes the header and uses both.
  4. Print the result of calling the function and reading the global variable.
Take Quiz

Keep learning

Related questions

View more