Skip to Content
Course content

72: The #include Directive: Angle Brackets vs Quotes

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I see this a lot when I'm reviewing code from developers moving into C: they treat the choice between <header.h> and "header.h" as a semantic rule. They think the brackets are a "flag" that tells the compiler, "This is a system library," and the quotes are a flag saying, "This is a file I wrote."

"Quotes are for local files, brackets are for system libraries"

If you believe that, you're thinking about it as a category of file rather than a search instruction. Let me show you why that's a misconception. Imagine you have a project with a local header called physics_engine.h. You've been using #include "physics_engine.h" because that's the "local" way.

But what happens if you run your compiler with an include flag, like -I./include, and you move that header into that directory? Suddenly, #include <physics_engine.h> works perfectly. The compiler doesn't suddenly think your physics engine is part of the C Standard Library; it just found the file using the path you provided. Conversely, if you accidentally copy stdio.h into your project folder, #include "stdio.h" will include your local copy instead of the system one, potentially breaking everything.

It's actually about the search priority

The real difference is the order of operations the preprocessor uses to find the file. When you use quotes, you're telling the compiler: "Start looking in the directory where this current source file lives. If you don't find it there, then go look in the system include paths."

When you use angle brackets, you're skipping the local directory entirely. You're saying: "Go straight to the system paths (and any paths I've added via the -I compiler flag)."

// The search logic looks roughly like this:

#include "my_lib.h" 
// 1. Check local folder -> Found? Stop.
// 2. Check -I paths -> Found? Stop.
// 3. Check /usr/include (etc) -> Found? Stop.
// 4. Error.

#include <my_lib.h> 
// 1. Check -I paths -> Found? Stop.
// 2. Check /usr/include (etc) -> Found? Stop.
// 3. Error.

I usually stick to the "convention" of brackets for system headers and quotes for project headers, but I do it because it signals intent to other humans, not because the compiler requires it for "system" vs "local" files. The crucial takeaway for you is that quotes are a superset of brackets—they do everything brackets do, but they check the local directory first.

One pro tip: avoid using quotes for standard headers like <stdlib.h>. Even if it works, it's a red flag during code reviews because it suggests you might have a naming collision in your local directory that you're unaware of.




📋 Practical Task

Fixing the Header Search Collision in a Math Library

You are working on a project where a teammate accidentally created a file named math.h in the local project directory. This is colliding with the system's <math.h> (which contains sin() and cos()).

Below is a snippet of main.c. The goal is to use the system's sqrt() function from the standard library, but the program is currently including the local, empty math.h instead, causing a compilation error because sqrt is not defined.

// Project structure:
// /project/main.c
// /project/math.h  <-- An empty file created by mistake

#include <stdio.h>
#include "math.h" // This is causing the problem

int main() {
    double val = 25.0;
    printf("Square root is: %f", sqrt(val));
    return 0;
}

Your Task: Modify the #include directive for the math library so that the compiler ignores the local math.h and forces the use of the system's standard math library. Explain why this change fixes the issue based on the search priority rules.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.