Skip to content
Devtoolry
Programming Languages

C Compiler Errors and Warnings Explained (Clang and GCC)

What common C compiler errors and warnings mean, from a missing semicolon to an undefined reference, with real Clang and GCC output and the fix for each.

By Avinash KoriPublished 5 min read

A C compiler error message pointing a caret at the end of a printf line where a semicolon is missing

A C compiler message has a fixed shape: the file, the line, the column, the kind of message and a sentence that is often more precise than it first looks. Once you can read that shape, most errors take seconds to fix.

This guide goes through the errors and warnings beginners and experienced programmers meet most often. Every message below is real output from Clang 21, the compiler behind the online C Compiler, with GCC's wording for the same mistake next to it, so you will recognise it whichever compiler you use. The C Compiler runs with -std=c17 -O2 -Wall, so paste any example there to see the message yourself.

How to read a compiler message

Output
main.c:4:22: error: expected ';' after expression
    4 |     printf("Hello\n")
      |                      ^
      |                      ;
  • main.c:4:22 is the file, line 4 and column 22.
  • error means the program was not built. A warning means it was built, but the compiler thinks the code is probably wrong.
  • The quoted line and the caret (^) show the exact position, and the last line is a fix-it hint: Clang suggests inserting ; there.

Two rules save a lot of time. Fix the first error first, because one mistake often causes several follow-up errors. And when the reported line looks fine, look at the line before it: a missing ; or } is only noticed when the next token arrives.

Syntax errors: expected ';'

The program above forgot the semicolon after printf(...). Clang reports the position where the semicolon should be. GCC reports the token that surprised it:

Output
error: expected ';' before 'return'

Both mean the same thing. Missing semicolons after a statement, after a struct definition (struct point { int x; }; needs the final ;) and unbalanced brackets are the usual causes.

Use of undeclared identifier

C
int total = 0;
for (int i = 0; i < 3; i++) totl += i;
Output
main.c:5:33: error: use of undeclared identifier 'totl'; did you mean 'total'?

GCC says 'totl' undeclared (first use in this function); did you mean 'total'?. The name is misspelt, used outside the block it was declared in (a variable declared inside a for loop does not exist after it), or used before its declaration.

Implicit declaration of function

Calling a function before the compiler has seen its declaration is an error in modern C:

Output
main.c:2:5: error: call to undeclared library function 'printf' with type 'int (const char *, ...)'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
main.c:2:5: note: include the header <stdio.h> or explicitly provide a declaration for 'printf'

The fix is in the note: include the header (<stdio.h> for printf, <stdlib.h> for malloc, <string.h> for strlen, <math.h> for sqrt), or declare your own function above main. GCC 11 only warns with implicit declaration of function 'printf', but GCC 14 and later make it an error too, so old tutorials that compile "with warnings" no longer build.

Incompatible integer to pointer conversion

C
int *p = 5;
Output
main.c:4:10: error: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int' [-Wint-conversion]

GCC's version reads initialization of 'int *' from 'int' makes pointer from integer without a cast. A pointer must hold an address, such as &x or the result of malloc, not a number. This usually means a missing & or *, or a function that returns int where you expected a pointer. Like implicit declarations, it is an error in Clang 16+ and GCC 14+.

Format string warnings: printf and scanf

These are warnings, so the program runs, which makes them dangerous:

C
double price = 3.5;
printf("%d\n", price);
Output
main.c:5:20: warning: format specifies type 'int' but the argument has type 'double' [-Wformat]
    5 |     printf("%d\n", price);
      |             ~~     ^~~~~
      |             %f

Passing a double for %d is undefined behaviour: in our test it printed 0, and other systems print a different wrong number. Use %f for double, %ld for long, %zu for size_t and %s for strings.

The scanf version is worse, because scanf writes through the argument:

C
int n;
scanf("%d", n);
Output
main.c:5:17: warning: format specifies type 'int *' but the argument has type 'int' [-Wformat]
main.c:5:17: warning: variable 'n' is uninitialized when used here [-Wuninitialized]

scanf needs the address, &n. Without it, the number is written to whatever address the garbage value in n happens to be. Reading input safely is covered in detail in Reading Input in C and C++.

Warnings that catch logic bugs

-Wall turns on warnings for code that is legal but almost always a mistake.

Assignment in a condition:

Output
main.c:5:11: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
    5 |     if (x = 5) printf("x is five\n");

x = 5 assigns, so the condition is always true and x is changed. You meant x == 5. GCC phrases it suggest parentheses around assignment used as truth value.

Missing return value:

C
int sign(int n) {
    if (n > 0) return 1;
    if (n < 0) return -1;
}
Output
main.c:6:1: warning: non-void function does not return a value in all control paths [-Wreturn-type]

For n == 0 the function returns nothing, and the caller gets an unpredictable value. GCC says control reaches end of non-void function. Add the missing return 0;.

Array index past the end:

Output
main.c:5:20: warning: array index 3 is past the end of the array (that has type 'int[3]') [-Warray-bounds]

An array of 3 elements has indexes 0, 1 and 2. The compiler can only catch constant indexes like this one; an out-of-range index computed at run time is not reported, so check loop bounds (i < n, not i <= n).

Unused variable: warning: unused variable 'unused' [-Wunused-variable] is harmless, but often points at a variable you meant to use, for example a misspelt accumulator.

Linker errors: undefined reference

Some errors come after compilation, from the linker that combines your code with the libraries:

C
int square(int n);

int main(void) {
    printf("%d\n", square(4));
}

Clang's WebAssembly linker reports wasm-ld: error: undefined symbol: square, and GCC on Linux reports:

Output
undefined reference to `square'
collect2: error: ld returned 1 exit status

The declaration promised that square exists, but no definition was found. Either the function body is missing, its name is spelt differently in the definition, or it lives in another file or library that was not linked. On your own machine, forgetting -lm when using <math.h> functions causes the same error for sqrt or pow; the online compiler links the maths library for you.

A checklist for any compiler error

  1. Read the first message completely, including the note: lines and fix-it hints.
  2. Go to the line and column, then check the line above it.
  3. For "undeclared" and "implicit declaration", check spelling, scope and #includes.
  4. Treat warnings as errors while learning: almost every warning in this guide marks a real bug.
  5. Reduce the program until the error disappears, and the last thing you removed is the cause.

The fastest way to learn these messages is to trigger them on purpose. Paste any snippet above into the C Compiler, break it in a different way and read what the compiler says. The same messages appear for C++ in the C++ Compiler, alongside the C++-specific ones.

Written by

Avinash Kori

Founder of Devtoolry

Avinash builds Devtoolry, a set of free developer tools that run entirely in the browser, and writes practical guides on the formats, encodings and techniques behind them.

Try it yourself

The free tools used in this article. They run in your browser, so nothing you paste is uploaded.