C Header Files
C - Header Files
Section titled “C - Header Files”A header file in C (typically with a .h extension) contains declarations and macro definitions intended to be shared across multiple source files (.c files). They act as interfaces, defining what functions, variables, types, and macros are available, without necessarily providing their implementation (definitions).
Two main types of header files:
- System Header Files: Provided by the C compiler and standard library (e.g.,
<stdio.h>,<stdlib.h>,<string.h>,<math.h>). They declare standard functions, types, and macros. - User-Defined Header Files: Created by programmers for their own projects to organize code and share declarations between their
.cfiles (e.g.,"my_graphics.h","network_utils.h").
Why Use Header Files?
Section titled “Why Use Header Files?”- Modularity: Break down large programs into smaller, manageable
.cfiles (modules). Header files define the public interface of each module. - Reusability: Declarations written once in a header file can be used in many
.cfiles by simply including the header. - Consistency: Ensures all source files use the same declarations for shared functions, types, and constants, preventing errors.
- Readability: Separates interface (declarations) from implementation (definitions), making code easier to understand.
- Reduced Compile Times (with proper use): Changes to implementation details in a
.cfile only require recompiling that file, not all files that use its interface (defined in the header).
Including Header Files (#include)
Section titled “Including Header Files (#include)”Use the #include preprocessor directive to insert the content of a header file into your source file.
Two forms:
1. #include <filename.h>
Section titled “1. #include <filename.h>”Used for system header files. The preprocessor searches for the file in a standard list of system directories (compiler-specific, often configurable).
#include <stdio.h> // Standard Input/Output#include <math.h> // Mathematical functions2. #include "filename.h"
Section titled “2. #include "filename.h"”Used for user-defined header files (your own project’s headers). The preprocessor typically searches for the file first in the same directory as the current source file, and then in the standard system directories (or other specified include paths).
#include "my_module.h"#include "config/settings.h"What Goes in a Header File?
Section titled “What Goes in a Header File?”Header files should generally contain declarations, not definitions that allocate storage or generate code.
- Function Prototypes (Declarations):
extern int calculate_sum(int a, int b); - Structure, Union, and Enum Definitions:
struct Point { int x, y; };,typedef enum { RED, GREEN, BLUE } Color; - Typedef Definitions:
typedef unsigned char BYTE; - Macro Definitions:
#define MAX_SIZE 100 - Global Variable Declarations (using
extern):extern int global_error_code;(The actual definitionint global_error_code = 0;goes in a.cfile).
What Should NOT Go in a Header File (Generally):
Section titled “What Should NOT Go in a Header File (Generally):”- Function Definitions (Implementations): Placing function bodies in headers leads to multiple definition errors if the header is included in more than one
.cfile. - Global Variable Definitions (without
static): Definingint my_global;in a header causes multiple definitions. - Large Amounts of Code: Headers should be concise interfaces.
Exception: static inline functions (C99) are often defined in header files as they don’t cause linker errors.
Include Guards
Section titled “Include Guards”If a header file is included multiple times in the same compilation unit (e.g., indirectly through other headers), its contents will be processed multiple times. This can lead to errors like redefinition of types or macros.
To prevent this, use include guards, a standard preprocessor idiom:
// --- my_module.h ---
#ifndef MY_MODULE_H // Check if MY_MODULE_H is not yet defined#define MY_MODULE_H // Define MY_MODULE_H to prevent future inclusions
// --- Header content goes here ---#define VERSION "1.0"
struct MyData { int id; char value[50];};
typedef struct MyData DataItem;
extern void process_data(DataItem *item);// --- End of header content ---
#endif // MY_MODULE_HThe first time my_module.h is included, MY_MODULE_H is not defined, so the preprocessor defines it and processes the header content. Subsequent inclusions in the same .c file will find MY_MODULE_H already defined, and the preprocessor will skip the content between #ifndef and #endif.
The guard macro name (MY_MODULE_H) should be unique to the header file (often based on the filename).
Some compilers support #pragma once as a simpler alternative, but include guards are more portable.