user13286424
user13286424

Reputation:

Different versions to prevent double include of header file, which is correct?

If I have a file called test.h and wanted to prevent double include of it (to prevent linker error) I was told to type:

#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED

But I have seen multiple versions of this, for example one told me to write:

#ifndef TEST_H
#define TEST_H

What's the difference and why can't I simply use the original name of my file like this:

#ifndef test.h
#define test.h

Edit: How does the preprocessor know that I am trying to prevent double include of a header file named test.h if the name after #ifndef is not important and can be anything like: #ifndef Dummy, and what's even the point of using a name if I am not going to use it, should they make it easier and let us only type:

#ifndef
#define

Upvotes: 1

Views: 1612

Answers (4)

Hitokiri
Hitokiri

Reputation: 3699

There is nothing different for the first two define options. The last option is not accepted because preprocessor does not accept the (.) as part of an identifier.

Sometimes it is necessary to select one of the several different header files to be included into your program:

#if SYSTEM_1
   # include "test1.h"
#elif SYSTEM_2
   # include "test2.h"
#endif

you simply put a macro name:

#define SYSTEM_1 "test1.h"
...
#include SYSTEM_1

UPDATE:

you cannot use:

#ifndef
#define

The preprocessor need a macro name. It like the if ... else statement. You can not if () {} else {}.

You can define anything you want event not use.

#ifndef NOTUSE
#define NOTUSE

For example, when you want to debug, you define DEBUG and you can use it when you want.

#ifdef DEBUG
printf(" debug here\n");
#endif /* DEBUG */

If you do not define DEBUG the printf function does not run.

Upvotes: 1

John Bollinger
John Bollinger

Reputation: 180256

The point of the question seems to be summed up nicely in the summary that was edited on:

Edit: How does the preprocessor know that I am trying to prevent double include of a header file named test.h if the name after #ifndef is not important and can be anything like: #ifndef Dummy,

The preprocessor doesn't know that you are specifically trying to prevent multiple inclusion, nor anything actionable about the name of the header file you are trying to protect. This is an application of the preprocessor's general purpose conditional compilation mechanism to the specific problem of accommodating (not actually preventing) multiple inclusion.

and what's even the point of using a name if I am not going to use it [...]

But you do use it. In the #ifndef directive. That the macro name referenced there is the same as the one #defined is crucial for this mechanism to work correctly.

The mechanism makes use of the fact that the preprocessor can test whether specific macro names are defined, and use the result as a condition for whether an associated section of a source file is compiled. This is what the #ifndef ... #endif is about. The #define ensures that compiling the section between causes the specified preprocessor macro to be defined, so that the #ifndef condition evaluates to false on subsequent inclusions of the same header. Thus, the specific choice of macro name is not significant, but the fact that it is distinct from all the macro names used by other headers (or that it is not, if that is done purposefully) is significant.

should they make it easier and let us only type:

#ifndef
#define

Again, this is a specific application of a general-purpose mechanism. The general purpose mechanism is for the definition of preprocessor macros and the testing of whether they are defined, which are parts of the larger preprocessor macro facility. This facility works in terms of specific macro names. Moreover, even if it were sensible, an empty macro name would not work for the purpose because (if used generally) it would not satisfy the necessary criterion of each header using a distinct macro name.

However, some C implementations agree with you that header guards could be easier. As a common (but not universal!) extension, some implementations recognize

#pragma once

appearing at the beginning of a header as a substitute for conditional-compilation-based inclusion guards.

Upvotes: 1

P.P
P.P

Reputation: 121397

What's the difference [..]

There's no difference as such. The macro name can be anything and the convention is use to the header name separated by underscore (TEST_H).

why can't I simply use the original name of my file like this

The macro name can't have . in it. So it's not allowed. The same rule for identifiers is also applicable for macro names. See 6.4.2 Identifiers.

You could instead have:

#ifndef test_h
#define test_h
#endif

or:

#ifndef test_header
#define test_header
#endif

But again, the convention is to use all caps with dot replaced by underscore and possibly with leading/trailing underscores.


Take this code example (not equivalent to macros - just for demonstrative purposes):

int flag = 0; 
if (flag == 0) {
    /* include this content */;
    flag = 1;
}
else {
    /* not included */
}

Here flag is the equivalent of the macro name. That's why the name itself does't bear any importance. All that matters is whether flag has been set or not.

should they make it easier and let us only type:
#ifndef
#define

Unfortunately, that's not valid syntax.

I understand general question and agree that this should have been better/easier. But this is historical. The preprocessor is an ancient thing (at least from the early 70's) and it's not going to change now :)

Upvotes: 2

Adrian Mole
Adrian Mole

Reputation: 51835

The first two options are semantically equivalent, and which is 'better' is subjective (the former is somewhat clearer, but involves more typing).

The third option is not possible, as macros in C can only contain letters, numerical digits (but not as the first character) and the underscore. The rules are the same as for any other type of identifier (variable and function names, for example); see this cppreference page for further details.

Upvotes: 2

Related Questions