12

I'm reading through some open-source code at the moment, and I see the following lines of code at the top of this C header file:

#ifndef __BASH_H__
#define __BASH_H__

I don't see __BASH_H__ referenced anywhere else in the codebase, so I suspected it is used indirectly (i.e. by the shell, a C compiler, or a 3rd-party library), not by the code itself.

I Googled for "BASH_H" and I saw it used by other open-source libraries (i.e. here and here), so I'm assuming I'm directionally correct in my assumption.

However the Google results don't include any official documentation on this declaration, its purpose, its usage(s), etc. I just see 2 pages total of search results, most of which look pretty irrelevant.

I'm assuming it's somehow related to bash, but I'm mystified by the lack of official docs. Can anyone point me in the right direction?

Richie Thomas
  • 3,073
  • 4
  • 32
  • 55
  • 1
    though here, the name of the macro is interesting in that it gives enough context to recognize the reason here. And it's not true it's not used (at all), as there's the `#ifndef` right there. – ilkkachu Nov 23 '22 at 17:42
  • 4
    In literally every C tutorial (with no exceptions) you'll find this very close to the start of the section about how to split your program into multiple files, because it's one of the ultra-basic concepts at the core of writing C code. I don't want to sound patronising, but if you have to ask this question then by definition I'm afraid you haven't put much work into learning the basics of C coding. – Graham Nov 24 '22 at 13:42
  • 3
    If you locate the matching `#endif` in that file, you might better understand how these "include guards" work. – JonathanZ Nov 24 '22 at 16:43
  • 1
    @Graham I initially chose the Unix channel because the name of the variable included `BASH` in it, so I assumed the question was at least partially relevant to the `bash` shell. I did do research and homework prior to posting here (as I outlined in the question itself), but it was all shell-specific research based on the aforementioned assumption. I now know better after reading Stephen Kitt's answer below and have now migrated the question from the Unix Q&A site over to StackOverflow. Sometimes you have to ask the wrong question in order to realize what the right question is. – Richie Thomas Nov 24 '22 at 20:39
  • @RichieThomas Fair enough. Most languages have dialect quirks though, so learning the language is a first step you really can't skip. Sometimes the best answer is "read a tutorial, you'll find out". :) – Graham Nov 25 '22 at 09:38
  • Does this answer your question? [Why are #ifndef and #define used in C++ header files?](https://stackoverflow.com/questions/1653958/why-are-ifndef-and-define-used-in-c-header-files) – SuperStormer Nov 26 '22 at 23:43
  • @SuperStormer the answer below from Steven Kitt answered my question, but thank you for the link. – Richie Thomas Nov 29 '22 at 15:48

1 Answers1

30

It’s a classic header guard: it ensures that the header is only included once. Imagine you have a file which says

#include "bash.h"
#include "bash.h"

The first #include will result in __BASH_H__ being defined. This will then result in the #ifndef in the second inclusion failing, so the “useful” contents won’t be included again.

Avoiding double declarations is useful for a number of reasons; the main one is that many elements in C can’t be declared twice, in particular structs.

(Having a single file include the a header twice is unlikely, but multiple inclusions can easily happen when headers include other headers: a.c includes b.h and c.h, and b.h includes c.h.)

There’s no external use for such guards, they are an implementation detail of the header file.

The name __BASH_H__ is chosen to have a good chance to be unique; any sufficiently distinguishable token could be used instead, idontwantbashhincludedtwice, single_bash_h, whatever. It doesn’t have a value, all that matters is whether it is defined or not. Its only use is in the pair of #ifndef/#define lines. (It’s commonly repeated as a comment alongside the matching #endif, but that doesn’t matter to the pre-processor.)

A common C compiler extension which achieves the same result is #pragma once.

Stephen Kitt
  • 2,786
  • 22
  • 32
  • I believe Visual C++ used to generate these tokens with UUIDs in them. Something like __STDAFX_H_INCLUDED_67528366_37EF_4FC6_93A8_EE21CD04523C and I always used to think it was some kind of magic incantation. – user253751 Nov 24 '22 at 12:29
  • 2
    I do note that `__BASH_H__` is a [**reserved identifier**](https://en.cppreference.com/w/c/language/identifier#Reserved_identifiers), and only usable by the implementation. User-defined identifiers, even for pragma guards, should never start with an underscore (nor, in C++ specifically, contain a double-underscore). – Matthieu M. Nov 24 '22 at 14:15