ProgramGuru

C Headers, Prototypes and Separate Modules

C Headers, Prototypes and Separate Modules

Two school programs need the same mark-total function. A declaration can describe how to call it, while one separately compiled source file supplies its definition.

A header normally exposes declarations and types shared by source files. A function declaration describes its contract; one corresponding definition supplies its body for linking.

  1. Explain

    Distinguish a callable declaration from a function definition and plan separate compilation.

  2. Trace

    Reuse the declared helper for 45 and 38.

  3. Apply

    Compile and link the files that supply a declared function.

Headers and Modules: follow the data

  1. Start

    Two school programs need the same mark-total function. A declaration can describe how to call it, while one separately compiled source file supplies its definition.

  2. Operation

    A header normally exposes declarations and types shared by source files. A function declaration describes its contract; one corresponding definition supplies its body for linking.

  3. Result

    Total: 75

A guided model of this example. The illustration explains the process; run the complete C program to check its output.

Understand the operation

The declaration lets the compiler check arguments and result type before a call. In a multi-file project, a marks.h header could declare int total(int, int), marks.c could define it, and main.c could include the header. Compile and link both source files.

Use an include guard in a repeatedly included header. Do not place ordinary externally linked function definitions or mutable global definitions into a header included by several files. The complete example keeps a declaration and definition in one file for a directly runnable first step.

Read the complete C program

This complete C17 program uses a small school example. Read declarations before the statements that use their values. Each printf format describes how the corresponding value is written to standard output.

C17 · complete program

#include <stdio.h>
static int total(int maths, int science);
static int total(int maths, int science) {
  return maths + science;
}
int main(void) {
  printf("Total: %d\n", total(40, 35));
  return 0;
}

Expected output

Total: 75
Run in C compiler →

Follow the values through the code

C17 · code used in this explanation

#include <stdio.h>
static int total(int maths, int science);
static int total(int maths, int science) {
  return maths + science;
}
int main(void) {
  printf("Total: %d\n", total(40, 35));
  return 0;
}

The prototype establishes two int parameters and an int result.

The definition performs the addition. The caller cannot invent a different contract simply because a prototype appears in another file.

Follow the worked calculation

  1. Read the starting values

    The prototype establishes two int parameters and an int result.

  2. Perform the operation

    The definition performs the addition. The caller cannot invent a different contract simply because a prototype appears in another file.

  3. Check the observable result

    Total: 75

    Total: 75
A guided model of this example. The illustration explains the process; run the complete C program to check its output.

Try a small variation

C17 · code used in this explanation

#include <stdio.h>
static int total(int maths, int science);
static int total(int maths, int science) {
  return maths + science;
}
int main(void) {
  printf("Total: %d\n", total(40, 35));
  return 0;
}

Reuse the declared helper for 45 and 38.

Worked answer

The call satisfies the same two-integer contract; a shared module can serve different callers without duplicating its implementation.

C17 · complete program

#include <stdio.h>
static int total(int maths, int science);
static int total(int maths, int science) {
  return maths + science;
}
int main(void) {
  printf("Total: %d\n", total(45, 38));
  return 0;
}

Expected output

Total: 83
Run in C compiler →

Build a real three-file project

Now separate the runnable example into three files in the same folder. The header shares the function declaration. Its guard remembers that the header has already been included in the current source file’s compilation, so the guarded contents are not processed twice.

marks.h · C17

#ifndef SCHOOL_MARKS_H
#define SCHOOL_MARKS_H
int total(int maths, int science);
#endif

marks.c · C17

#include "marks.h"
int total(int maths, int science) {
  return maths + science;
}

main.c · C17

#include <stdio.h>
#include "marks.h"
int main(void) {
  printf("Total: %d\n", total(40, 35));
  return 0;
}

marks.c supplies the function body. It includes its own header so the compiler can detect a conflict between that declaration and the definition. main.c includes the declaration so its call can be checked. Unlike the earlier single-file helper, this shared function has no static keyword: the linker must be able to find it from the other source file.

Unix-like shell command to compile and link both C source files:

cc -std=c17 -Wall -Wextra -Wpedantic main.c marks.c -o school
./school

Expected output:

Total: 75

If you build only main.c, the declaration can let compilation succeed, but the linker still needs the definition of total. The header is shared information; including it does not compile marks.c for you. Run this multi-file example in your local compiler; the course’s online editor accepts one source file.

Recognize the important boundaries

Including a header is not a substitute for linking the source or library that defines its declared functions.

Avoid conflicting declarations across files. A successful isolated translation cannot establish that incompatible cross-file types are a sound program.

Check your understanding

Choose the answer, then compare the reasoning for every option.

Does including a function prototype provide the function body to the linker?
Choose one answer. You can try again.

Answer and explanation

No; link the implementation too.

Correct. A declaration and definition serve different roles.

Use the idea independently

A header normally exposes declarations and types shared by source files. A function declaration describes its contract; one corresponding definition supplies its body for linking.

Continue with guards and macros.

Language reference: WG14 C11 committee draft. These examples use the C17-compatible subset of the explained language features.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: C Preprocessor, Macros and Header Guards →