Compiler and Linker Flags
This chapter catalogs the flags that matter most: warnings, language standard, optimization, debugging, sanitizers, and linker options.
Why This Matters
Flags change how strictly the compiler checks your code and how aggressively it optimizes. A good default flag set catches bugs early; the wrong flags can hide them or introduce new ones.
Prerequisites
c.build.6— compilers.
Core Concept
Flags are passed to the compiler driver (cc/gcc/clang/cl). Some apply to compilation, some to linking, some to both.
Important Flags (GCC/Clang)
| Flag | Effect |
|---|---|
-std=c17 | language standard |
-Wall -Wextra | enable common warnings |
-pedantic | strict conformance warnings |
-Werror | treat warnings as errors |
-g | include debug info |
-O0/-O1/-O2/-O3/-Os | optimization level |
-fsanitize=address,undefined | ASan + UBSan |
-fPIC | position-independent code |
-shared | build a shared library |
-static | static link |
-I<dir> | add include path |
-L<dir> | add library path |
-l<name> | link library |
-D<macro> | define macro |
-MMD -MP | dependency files |
MSVC equivalents use / (e.g., /std:c17, /W4, /O2, /Zi, /I, /D).
Examples
A robust debug build
cc -std=c17 -Wall -Wextra -pedantic -g -fsanitize=address,undefined main.c -o app
A release build
cc -std=c17 -O2 -DNDEBUG main.c -o app
How It Works
The driver passes compilation flags to the compiler proper and linker flags to the linker. Some flags (like -g, -O2) affect the generated code; others (-I, -L, -l) affect how files are found and combined.
Variations
Warning flags
-Wall does not enable *all* warnings despite the name. -Wextra adds more; -Wconversion, -Wshadow, -Wstrict-aliasing add still more.
Optimization and UB
Optimization can expose UB that debug builds hide (c.opt.2). Always test at multiple optimization levels.
Common Mistakes
- Not using
-Wall -Wextra. - Using
-Werrorin released code (new compiler versions may add warnings). - Forgetting
-gfor debug builds. - Confusing
-O(capital letter) with-o(output file).
Undefined Behavior
- Flags themselves do not cause UB, but aggressive optimization can make
existing UB manifest differently.
Portability
- Flag names differ between GCC/Clang and MSVC. Abstract them in build systems.
Under the Hood
-g emits DWARF debug sections (c.debug.2). -O* enables optimization passes (c.opt.1). -fsanitize=... instruments the code with runtime checks (c.debug.3).
Practical Usage
- Default to
-std=c17 -Wall -Wextra -pedantic. - Use
-fsanitize=address,undefinedduring development. - Use
-O2 -DNDEBUGfor release. - Put flags in the build system, not scattered in scripts.
Exercises
1. Compile a buggy program with and without -Wall -Wextra and note the difference. 2. Build with -fsanitize=address,undefined and run a program with a known UB. 3. Compare generated code at -O0 and -O2.
Deep Challenge
Construct a small program with a bug that only manifests at -O2 (e.g., a strict-aliasing violation), explain why, and fix it. Document how -fsanitize=undefined helps find it.
Related Concepts
c.opt.1— optimization levels.c.debug.3— sanitizers.c.build.7— build systems.
References
- GCC manual, Clang documentation, MSVC documentation.
Verification
- Flag effects are documented compiler behavior.
VERIFIED - No example was executed during generation unless noted. `Execution not
verified.`
Progress
- [ ] Read
- [ ] Understand
- [ ] Complete examples
- [ ] Complete exercises
- [ ] Complete deep challenge
Concept checkboxes
- [ ] Language standard flags
- [ ] Warning flags
- [ ] Optimization flags
- [ ] Debug and sanitizer flags
- [ ] Linker flags
Mastery levels
| Concept | Current level (0–8) | Target level |
|---|---|---|
| c.build.flags | 0 | 6 |