GCC will happily compile code that has serious bugs in it. By default, it only shows errors that prevent compilation. Everything else — uninitialized variables, signed/unsigned mismatches, implicit function declarations — it silently ignores. These flags change that.

The Three You Always Enable

gcc -Wall -Wextra -Werror -o program program.c

-Wall — Enable common warnings

Despite the name, -Wall does not enable all warnings. It enables the warnings GCC considers most important. This includes:

  • Uninitialized variables
  • Implicit function declarations (using a function before declaring it)
  • Unused variables
  • Missing return statements
  • Signed/unsigned comparison mismatches
  • Potentially misused format strings
#include <stdio.h>

int main() {
    int x;
    printf("%dn", x);   /* -Wall catches: 'x' is used uninitialized */
    return 0;
}
gcc -Wall -o program program.c
warning: 'x' is used uninitialized [-Wuninitialized]

-Wextra — Enable additional warnings

-Wextra enables warnings not covered by -Wall. These tend to be slightly more opinionated but equally useful:

  • Unused function parameters
  • Missing field initializers in structs
  • Comparisons that are always true or false
  • Empty body in if/else/for/while
#include <stdio.h>

void greet(char *name) {
    printf("Hellon");
    /* -Wextra catches: unused parameter 'name' */
}

int main() {
    greet("Alice");
    return 0;
}

-Werror — Treat warnings as errors

Without -Werror, warnings do not stop compilation. You see the warning, think “I’ll fix that later,” and never do. -Werror makes warnings stop the build, forcing you to address them.

gcc -Wall -Wextra -Werror -o program program.c
/* Now the program with an uninitialized variable will not compile */

Use this in your development builds. Some projects only use it in CI to enforce quality without blocking individual developers who might intentionally leave something unfinished.

Other Useful Flags

-Wshadow — Catch variable shadowing

#include <stdio.h>

int x = 10;

void func() {
    int x = 20;          /* shadows the global x */
    printf("%dn", x);   /* which x? */
}

int main() {
    func();
    return 0;
}
gcc -Wshadow -o program program.c
warning: declaration of 'x' shadows a global declaration [-Wshadow]

-Wformat=2 — Stricter format string checking

#include <stdio.h>

int main() {
    char *user_input = get_user_input();
    printf(user_input);   /* format string injection vulnerability */
    return 0;
}
gcc -Wformat=2 -o program program.c
warning: format not a string literal and no format arguments [-Wformat-nonliteral]

Format string vulnerabilities are a real class of security bug. -Wformat=2 catches printf(variable) instead of printf("%s", variable).

-Wwrite-strings — Warn on string literal modification

#include <stdio.h>

int main() {
    char *str = "hello";   /* should be const char* */
    str[0] = 'H';          /* undefined behaviour */
    return 0;
}
gcc -Wwrite-strings -o program program.c
warning: assignment discards 'const' qualifier [-Wdiscarded-qualifiers]

-Wconversion — Warn on implicit type narrowing

#include <stdio.h>

int main() {
    double d = 3.99;
    int i = d;          /* silently truncates to 3 */
    printf("%dn", i);
    return 0;
}
gcc -Wconversion -o program program.c
warning: conversion from 'double' to 'int' may change value [-Wfloat-conversion]

The Recommended Flag Set

gcc -Wall -Wextra -Werror -Wshadow -Wformat=2 -Wwrite-strings -o program program.c

For security-sensitive code or production systems, add:

gcc -Wall -Wextra -Werror -Wshadow -Wformat=2 -Wwrite-strings 
    -Wconversion -Wpedantic -std=c11 -o program program.c

-Wpedantic and -std=c11

-Wpedantic enforces strict ISO C compliance — it flags code that relies on GCC extensions or constructs that are technically undefined by the standard. -std=c11 sets the language standard explicitly to C11, so you know exactly what standard your code targets.

Runtime Detection with AddressSanitizer

Static warnings catch problems at compile time. AddressSanitizer catches memory bugs at runtime:

gcc -g -fsanitize=address -o program program.c
./program

This instruments your binary to detect buffer overflows, use-after-free, and memory leaks at runtime, printing the exact file and line number where the bug occurred. Use this during development and testing. Remove it from release builds (it adds ~2x overhead).

TL;DR

  • -Wall — enables common warnings. Always use this.
  • -Wextra — enables additional warnings. Always use this.
  • -Werror — turns warnings into errors. Use in dev/CI.
  • -Wshadow — catches variable shadowing.
  • -Wformat=2 — catches format string vulnerabilities.
  • -Wwrite-strings — catches string literal modification.
  • -fsanitize=address — runtime memory bug detection.
  • Minimum recommended: gcc -Wall -Wextra -Werror -o prog prog.c
  • For a full reference of GCC flags beyond warnings, see our guide on how to compile C code with GCC