Macros (#define)
An object-like macro is the simplest form of preprocessor substitution: give a name to a piece of text with #define, and every later occurrence of that name in the source is replaced, character for character, before compilation even starts.
#include <stdio.h>
#define PI 3.14159
int main(void)
{
double radius = 2.0;
double area = PI * radius * radius;
printf("Area: %f\n", area);
return 0;
}After preprocessing, every PI in the file is gone — replaced by the literal text 3.14159. The compiler never sees a symbol called PI at all; it only ever sees the number.
It Is Text Substitution, Not a Variable
This is the single most important thing to internalize about macros: #define does not create a typed, scoped constant the way a const int or a variable declaration does. It creates a raw text replacement rule that the preprocessor applies blindly, everywhere in the file, with no awareness of C syntax, types, or scope.
#define PI 3.14159
int main(void)
{
int PI = 5; /* Expands to: int 3.14159 = 5; -- syntax error! */
return 0;
}That snippet fails to compile with a confusing error pointing at 3.14159, not at PI — because by the time the compiler sees the code, PI no longer exists as a name. This is a classic beginner gotcha: using a common word as a macro name can silently clash with an unrelated identifier used somewhere far away in the code (including inside library headers you include).
The ALL_CAPS Naming Convention
Because macros are invisible to the type system and can be expanded anywhere, the C community adopted a strong convention: write macro names in ALL_CAPS. Seeing MAX_BUFFER_SIZE or PI in all caps is an instant visual signal to any reader that this identifier is a preprocessor substitution, not a real variable or function — so they know to think about it differently (no scope, no type, pure text).
#define MAX_USERS 100— a macro constant, all capsint maxUsers = 100;— a real, typed, scoped variable, not all capsMixing the two styles up is a common source of confusion in code review
Removing a Macro With #undef
A macro definition stays active for the rest of the file (or until the end of the translation unit) unless you explicitly remove it with #undef. This is occasionally useful when a header defines a macro name you need to reuse for something else afterward.
#define BUFFER_SIZE 256 /* ... code that uses BUFFER_SIZE ... */ #undef BUFFER_SIZE #define BUFFER_SIZE 512 /* redefine safely after #undef */