Question
In C, where are MIN and MAX defined, if they are defined at all?
What is the best way to implement MIN and MAX as generically and as type-safely as possible? If useful, prefer compiler extensions or built-in features available in mainstream C compilers.
Short Answer
By the end of this page, you will understand that standard C does not provide universal MIN and MAX macros, why naïve macro versions are dangerous, and how to build safer alternatives. You will also see practical approaches using plain macros, static inline functions, C11 _Generic, and GNU-style compiler extensions.
Concept
In C, MIN and MAX are a common need, but they are not part of the core C standard library as universal macros.
You may have seen them in:
- operating-system headers
- third-party libraries
- codebases with custom utility headers
- platform-specific APIs such as Windows headers
That can create confusion, because a program that compiles in one environment may fail in another if it assumes MIN or MAX already exist.
Why this matters
Choosing the smaller or larger of two values sounds simple, but in C the implementation details matter because of:
- multiple evaluation of macro arguments
- type conversions between signed and unsigned values
- lack of true generics in older C versions
- side effects such as
i++being evaluated more than once
A naïve macro like this is common:
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
It looks correct, but it can evaluate a or b more than once. That makes it unsafe for expressions with side effects.
Mental Model
Think of MIN and MAX as a machine that compares two boxes and returns one of them.
A bad machine opens the same box multiple times before deciding. If opening a box changes its contents, the result becomes unreliable.
That is what happens with unsafe macros:
MIN(i++, j)is like opening theibox, changing it, then opening it again- the act of checking changes the value being checked
A better machine:
- opens each box exactly once
- labels what type of box it is handling
- compares safely
- returns the correct box without unexpected changes
So the real goal is not just “find the smaller value.” The goal is “find the smaller value without surprising behavior.”
Syntax and Examples
1. Simple macro approach
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
Usage:
int x = 10;
int y = 20;
int small = MIN(x, y);
int large = MAX(x, y);
This is short and portable, but unsafe for expressions with side effects.
2. Safer static inline functions for specific types
static inline int min_int(int a, int b) {
return a < b ? a : b;
}
static inline double max_double(double a, double b) {
return a > b ? a : b;
}
Usage:
int a = 4;
int b = ;
m = min_int(a, b);
Step by Step Execution
Consider this unsafe macro:
#define MIN(a, b) ((a) < (b) ? (a) : (b))
Now run:
int i = 2;
int j = 5;
int m = MIN(i++, j);
What happens step by step
MIN(i++, j)expands to:
((i++) < (j) ? (i++) : (j))
-
The condition
(i++) < (j)is evaluated.i++produces2- then
ibecomes3 2 < 5is true
-
Because the condition is true, the true branch
(i++)is evaluated.i++produces3
Real World Use Cases
Bounds checking
size_t safe_len = MIN(input_len, buffer_size);
Used when copying data into a buffer to avoid overflow.
Clamping values
MIN and MAX are often combined:
int clamped = MAX(0, MIN(value, 100));
Useful for percentages, scores, volume levels, and UI limits.
Image and graphics code
When computing color channels or pixel boundaries:
int brightness = MIN(raw_brightness, 255);
Parsing and validation
When reading numeric input from files, APIs, or user input:
timeout = MAX(timeout, 1);
This ensures a minimum valid timeout.
Memory and I/O operations
When reading chunks of data:
size_t chunk = MIN(remaining_bytes, block_size);
This is common in file readers, network code, and streaming logic.
Real Codebase Usage
In real projects, developers usually avoid relying on a random global MIN or MAX already existing. Instead, they choose a predictable pattern.
Common patterns
Utility header with project-defined helpers
A codebase may define its own helpers in one shared header:
static inline size_t min_size(size_t a, size_t b) {
return a < b ? a : b;
}
This is explicit and easy to debug.
Guarding macro definitions
If macros are used, teams often avoid conflicts with existing headers:
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
This reduces redefinition issues, though it does not solve the side-effect problem.
Type-specific helpers for important domains
For example, networking code may use size_t, while math code may use double:
{ a < b ? a : b; }
{ a > b ? a : b; }
Common Mistakes
1. Assuming MIN and MAX are standard C
Broken assumption:
int x = MIN(3, 4); /* may fail if MIN is not defined */
How to avoid it:
- define your own utility
- or use a library/platform header only if you know it is available
2. Using side effects in macro arguments
Broken code:
#define MIN(a, b) ((a) < (b) ? (a) : (b))
int i = 1;
int m = MIN(i++, 10);
Problem:
i++may run more than once
Fix:
- do not pass side-effect expressions to unsafe macros
- or use
static inline,_Generic, or a GNU single-evaluation macro
3. Ignoring signed/unsigned conversions
Broken code:
int a = ;
b = ;
m = MIN(a, b);
Comparisons
| Approach | Portable | Single evaluation | Type-safe | Generic | Notes |
|---|---|---|---|---|---|
| Simple macro | Yes | No | Weak | Yes | Short, but unsafe with side effects |
static inline function | Yes | Yes | Strong for one type | No | Best simple portable option |
C11 _Generic + inline functions | C11+ | Yes | Good | Limited by listed types | Standard way to emulate generics |
| GNU statement-expression macro | GCC/Clang GNU mode |
Cheat Sheet
Key fact
Standard C does not define universal MIN and MAX macros.
Unsafe but common
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
- portable
- generic
- may evaluate arguments more than once
Safe for one type
static inline int min_int(int a, int b) {
return a < b ? a : b;
}
- portable
- evaluates once
- one type per function
Standard generic option in C11+
#define min(a, b) _Generic((a) + (b), \
int: min_int, \
double: min_double \
)(a, b)
- type-based dispatch
- explicit supported types
GNU extension option
FAQ
Are MIN and MAX part of the C standard library?
No. Standard C does not provide universal MIN and MAX macros for general use.
Why is the usual #define MIN(a,b) macro unsafe?
Because macro arguments can be evaluated more than once. Expressions like i++ can therefore produce unexpected results.
What is the safest portable way to implement MIN and MAX in C?
Type-specific static inline functions are usually the safest and most portable practical option.
How can I make MIN and MAX generic in standard C?
Use C11 _Generic together with type-specific static inline functions.
Is there a one-line generic solution for GCC or Clang?
Yes. GNU statement expressions with __auto_type are a common approach, but they are compiler extensions, not standard C.
Can I use MIN and with different numeric types?
Mini Project
Description
Create a small numeric utility header for C that provides safe minimum and maximum operations for common types. This project demonstrates the trade-offs between portability, safety, and generic behavior, and mirrors what real codebases often do in shared utility headers.
Goal
Build a reusable min/max utility that evaluates arguments once and works for several common numeric types.
Requirements
- Create type-specific
static inlinefunctions for at leastint,long, anddouble. - Add C11
_Genericmacros namedminandmaxthat dispatch to the correct function. - Write a
mainfunction that tests each supported type. - Include at least one example that would be unsafe with a plain macro, such as
i++. - Print the results so the behavior can be verified easily.
Keep learning
Related questions
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.
C Pointer to Array vs Array of Pointers: How to Read Complex Declarations
Learn the difference between pointer-to-array and array-of-pointers in C, plus a simple rule for reading complex declarations correctly.