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
On this page
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
main.c:4:22: error: expected ';' after expression
4 | printf("Hello\n")
| ^
| ;main.c:4:22is the file, line 4 and column 22.errormeans the program was not built. Awarningmeans 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:
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
int total = 0;
for (int i = 0; i < 3; i++) totl += i;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:
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
int *p = 5;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:
double price = 3.5;
printf("%d\n", price);main.c:5:20: warning: format specifies type 'int' but the argument has type 'double' [-Wformat]
5 | printf("%d\n", price);
| ~~ ^~~~~
| %fPassing 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:
int n;
scanf("%d", n);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:
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:
int sign(int n) {
if (n > 0) return 1;
if (n < 0) return -1;
}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:
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:
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:
undefined reference to `square'
collect2: error: ld returned 1 exit statusThe 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
- Read the first message completely, including the
note:lines and fix-it hints. - Go to the line and column, then check the line above it.
- For "undeclared" and "implicit declaration", check spelling, scope and
#includes. - Treat warnings as errors while learning: almost every warning in this guide marks a real bug.
- 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.
C Compiler
Compile and run C code online with Clang 21, a GCC-compatible compiler: pick C89 (ANSI C), C99, C11, C17 or C23 and add stdin input. Your code stays private.
C++ Compiler
Compile and run C++20 code online with Clang 21, libc++ and stdin input. Programs compile to WebAssembly and run in your browser, so your code stays private.