1

I have often seen code like

#ifndef HEADERFILE_H
#define HEADERFILE_H
// some declarations in
// the header file.
#endif

I want to know what #define HEADERFILE_H define HEADERFILE_H to?

I tried doing

cout<<HEADERFILE_H<<endl;

but I am getting

error: expected expression
zeitgeist
  • 852
  • 12
  • 19
  • If you `#define TEST` and you later use it somewhere, `TEST` is replaced with nothing. E.g.: `int x = foo(TEST);` is equivalent to `int x = foo();`. As @ThomasJager pointed out, in this case the "empty" `#define` is used to include the header only once. – Luca Polito Sep 18 '21 at 12:53
  • 1
    You seem to be switching languages mid-stream. You talk of C, but the code is C++. Which is it? – Tom Karzes Sep 18 '21 at 12:55
  • I wanted to use printf but didn't know the type, so I used cout – zeitgeist Sep 18 '21 at 13:06

3 Answers3

3

A define preprocessing directive has the form # define identifier preprocessing-tokens, ending with a new-line character. The preprocessing-tokens is a list of zero or more preprocessing tokens. It may be empty, that is, it may have zero tokens. This means, that when the identifier is encountered in a place where macro replacement occurs, it will be replaced with nothing.1

Tests of the form #ifdef identifier, #ifndef identifier, or defined identifier in a #if or #elif directive test whether identifier is defined or not. If it was not defined (or its definition was removed with the #undef directive), then the test indicates it is not defined. If it was defined, then the test indicates it was defined, even if the definition is for zero tokens.

A definition with zero tokens is different from no definition at all, and defined identifier will evaluate as true for the former and false for the latter.

Footnote

1 If the list does have tokens, then identifier will be replaced with those tokens and # and ## operators among them will be applied. A preprocessing token is largely an identifier (like foo34), a constant (like 3, 4u, or 1.8e4), one of the C operators or special characters (like * or +=), or certain other components of the C language.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Do you mean to say that the preprocessor maintains a map of identifier to preprocessor tokens. The only thing in my case is the preprocessor tokens is empty? Also #undef removes from the map? – zeitgeist Sep 18 '21 at 13:27
  • 1
    @Heroman: It is up to each C compiler (or other C implementation) to manage its data in some way. The C standard just says what behavior results from using macro replacement and `#define` directives, not how a compiler has to implement them. Most compilers likely maintain a map or something similar. – Eric Postpischil Sep 18 '21 at 13:58
2

This is a language idiom (I will comment it):

#ifndef HEADERFILE_H

Between this, and the last #endif everything is included in compilation, but only if HEADERFILE_H has not been defined before.

#define HEADERFILE_H

The first thing we do in the block is to #define the identifier, so next time we find this fragment again later, the contents between #ifndef and #endif will not be #included again (because of the identifier declaration).

// some declarations in
// the header file.

this block will be included only once, even if you #include this file several times.

#endif

and this marks the end of the protected block.

It is common to include some file that, indeed, #includes another, and that file includes another, leading to a point in which you don't know which files have been included and which don't. This phrasing allows you to be protected, and to be able to #include the same file several times (normally you cannot, as some definitions cannot be repeated in the same compilation unit, e.g. declarations) the lines above will include the contents and define the identifier, making next inclussions (that are effectively done) not to include the contents, as the identifier appears as #definen in second and ulterior times.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
0

It actually defines "nothing else than itself". That is: you may define a macro without assigning it a specific value. Since you can check if a given macro is defined or not, you therefore can ask for the simple "existence" of a given macro.

This is useful to indicate a context (for example, if you're compiling for a given OS) and/or the availability of some resources.

In this particular example, this is a called a "guard": it will define itself if this hasn't been done first before, as well as including the rest of the file, which is totally embedded in the #ifdef … #endif clause.

This is used to implement a kind of require_once, that is something that will be included if needed, but not multiple times. This is required when you are defining functions or declaring variables at a global scope, for instance.

Obsidian
  • 3,719
  • 8
  • 17
  • 30
  • Thanks, what do you mean by "nothing else than itself". Is it a numerical value? I want to know the internals. – zeitgeist Sep 18 '21 at 13:07
  • 2
    `#define HEADERFILE_H` does not define `HEADERFILE_H` to be “itself,” so it does not define it to be “nothing else than itself.” It defines `HEADERFILE_H` to be the empty sequence of preprocessor tokens. – Eric Postpischil Sep 18 '21 at 13:07