Purpose of #ifndef and #define?

I always see header files starting with

#ifndef BITMAPS_H
#define BITMAPS_H

and end with:

#endif

Why do we have to do this?

Why do external files have to end in .h?


What is the correct way of including .h files in my .ino?

#include "bitmaps.h"

or

#include <bitmaps.h>
1 Like

C and C++ use a special component in their compilers called a preprocessor. It’s basically a fancy copy-paste machine.

Firstly a breakdown of what all the different preprocessor words mean (you can skip this if you’re sure you know how they work).

#define defines a word to mean something else.
E.g. #define FIVE 5 would result in all instances of FIVE being replaced with 5.

#if tests if a condition is true.
#else provides an alternative case for an #if, in case it is not true.
#endif ends an #if
e.g.

#if VERSION > 5
useNewFeature();
#else
useOldFeature();
#endif

#ifdef tests if a word is defined and #ifndef does the opposite - it tests if a word has not been defined.
e.g.

#define FIVE
#ifdef FIVE
// This is used
#else
// This isn't
#endif

So now that’s out of the way, let’s examine this.

#ifndef BITMAPS_H
#define BITMAPS_H
// lots of bitmaps
#endif

The correct name for this sequence is a “include guard”.

This says ‘if BITMAPS_H isn’t defined, define it, then look at this C++ code’ which implicitly means ‘if BITMAPS_H is defined, ignore all this code’.
What this results in is a block of code that can only be examined once. This is done for a good reason - trying to read certain bits of code twice will upset the compiler because it will think you are trying to redefine something you have already stated.
The compiler doesn’t realise it’s the same file and doesn’t know to ignore it unless you use that special define sequence.
If your wondering why the compiler might try to read it twice, that’s because of how #include works.

#include is basically a copy-paste. #include "file.h" says 'copy the contents of file.h and paste it all here. This means that if file.h gets #included more than once, you’ll have duplicate sets of code, which is why you need the include guards - to make sure the compiler ignores the duplicates.


As you’ve pointed out, there are two kinds of includes, and they both have different behaviour. The difference is where the preprocessor looks for the file.

If you use the quote syntax #include "bitmaps.h" then the preprocessor will look for the file locally. E.g. if you had a file “Project/Main.h” and it had a line #include "Other.h", the preprocessor would look for “Project/Other.h”.

The angle bracket syntax on the other hand, looks for the file in a specially designated library folder and it typically used for external libraries.

What this means is that for files local to your project you want to use the quote-style #include "bitmaps.h" and for external librarys you want to use angle-bracket-style, like when you #include <Arduboy2.h>.

I hope that all makes sense.


Post Script:
There are a few details I’ve left out like #if defined(WORD) and #pragma once, but you don’t need to know about those unless you’re really curious.

5 Likes

Thanks for the very in depth reply!

I guess a way that it could be included twice is in this case:

You include bitmaps.h in your main file
You include xyz.h also in main file
xyz.h includes bitmaps.h itself within xyz.h

would this be a way it could be called twice if the #ifndef was not used?

I guess it sort of has the same effect as a PHP include_once statement?[quote=“Pharap, post:2, topic:3592”]
What this means is that for files local to your project you want to use the quote-style #include “bitmaps.h” and for external librarys you want to use angle-bracket-style, like when you #include <Arduboy2.h>.
[/quote]

Oh i get it now

No problem.

Precisely.

Another example:
Main.h includes Circle.h and Rectangle.h
Circle.h includes Point.h
Rectangle.h includes Point.h

Based on the description on php.net yes, it’s a different mechanism to achieve the same effect of having code only declared once. In C++'s case though, trying to define something twice is a compile-time error so your program wouldn’t even compile. I suspect PHP is a bit more forgiving.

1 Like

Just use #pragma once at the beginning of your header files instead of macros #ifdef #endif to safe guard your includes. It has the same effect.

It is:

  • largely supported
  • more meaningful for beginners
  • helps to remove noise code lines in header files
  • can be optimized by certain compilers
  • no need to create unique macro names
2 Likes

It also breaks under certain weird conditions involving hard links, sym links and mounting and isn’t supported by older compilers (older being around early 2000s).

(I still use and advocate it, but somebody has to mention the small disclaimer. :P)

1 Like

To be more precise, quote syntax means look for the file locally and then if it isn’t found locally continue searching for it as if you had used angle bracket syntax.

So if you wanted, you could always use quotes, never angle brackets. If it isn’t a local file, the external path will still be searched. However, by using angle brackets when you know it’s not a local file, it makes the code clearer and can help with solving “file not found” type errors. It helps to indicate where the file is actually expected to be located.


This is not a rule but a convention. The .h extension indicates it’s a header file. The traditional rule of thumb is that header files declare definitions (such as #define statements), and may include other header files, but don’t contain statements that actually generate any code. Another purpose of header files is to provide function prototypes and class declarations, but because of extra pre-compiler work performed by the IDE, declaring function prototypes is rarely required in the Arduino world with a properly written sketch.

You will find that many people actually do put code generating statements in header files. Putting bitmaps, music scores and other constant data in a header file is somewhat acceptable for Arduino sketches for simplicity, due to the way IDE compiling works. Otherwise, I personally don’t feel functions or other code should go in header files but I don’t want to start any holy wars about it (which has already been done to death). (And I’ll add that there are some exceptions, such as C++ templates.)

1 Like

For the sake of pedantry, technically how both quote-includes and angle-bracket-includes search for files is implementation defined (“searches a sequence of implementation-defined places for a header”/“The named source file is searched for in an implementation-defined
manner”), so the quote-include could be configured to search somewhere else and the angle-bracket-include could search locally.
The angle-bracket-include also technically doesn’t have to be a filename, or even a URL.
“How the places are specified or the header identified is implementation-defined.”

True. I didn’t want to go to that level of detail to avoid information overload, but I did want to point out that (at least for Arduino) quote-includes can find files beyond the local directory. This was in anticipation of someone asking: Why does #include "Arduboy2.h" work, as I’ve seen in other sketches, instead of requiring #include <Arduboy2.h> ?