为什么只定义尚未定义的宏?

在我们的 C 代码库中,我看到每个宏都是这样定义的:

#ifndef BEEPTRIM_PITCH_RATE_DEGPS
#define BEEPTRIM_PITCH_RATE_DEGPS                   0.2f
#endif


#ifndef BEEPTRIM_ROLL_RATE_DEGPS
#define BEEPTRIM_ROLL_RATE_DEGPS                    0.2f
#endif


#ifndef FORCETRIMRELEASE_HOLD_TIME_MS
#define FORCETRIMRELEASE_HOLD_TIME_MS               1000.0f
#endif


#ifndef TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS       50.0f
#endif

执行这些定义检查而不仅仅定义宏的基本原理是什么?

#define BEEPTRIM_PITCH_RATE_DEGPS                   0.2f
#define BEEPTRIM_ROLL_RATE_DEGPS                    0.2f
#define FORCETRIMRELEASE_HOLD_TIME_MS               1000.0f
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS       50.0f

我在网上找不到任何关于这种做法的解释。

6295 次浏览

I do not know the context but this can be used to give the user the availability to override the values set by those macro definitions. If the user explicitly defines a different value for any of those macros it will be used instead of the values used here.

For instance in g++ you can use the -D flag during compilation to pass a value to a macro.

This is done so that the user of the header file can override the definitions from his/her code or from compiler's -D flag.

This allows you to override the macros when you're compiling:

gcc -DMACRONAME=value

The definitions in the header file are used as defaults.

Any C project resides on multiple source files. When working on a single source file the checks seem to (and actually) have no point, but when working on a large C project, it's a good practice to check for existing defines before defining a constant. The idea is simple: you need the constant in that specific source file, but it may have been already defined in another.

As I said in the comment, imagine this situation:

foo.h

#define FOO  4

defs.h

#ifndef FOO
#define FOO 6
#endif


#ifndef BAR
#define BAR 4
#endif

bar.c

#include "foo.h"
#include "defs.h"


#include <stdio.h>


int main(void)
{
printf("%d%d", FOO, BAR);
return 0;
}

Will print 44.

However, if the conditional ifndef was not there, the result would be compilation warnings of MACRO redefinition and it will print 64.

$ gcc -o bar bar.c
In file included from bar.c:2:0:
defs.h:1:0: warning: "FOO" redefined [enabled by default]
#define FOO 6
^
In file included from bar.c:1:0:
foo.h:1:0: note: this is the location of the previous definition
#define FOO 4
^

You could think about a framework/library that gives to the user a default preset that allow the user to compile and work on it. Those defines are spreaded in different files and the final user is advised to include it's config.h file where he can config its values. If the user forgot some define the system can continue to work because of the preset.

Using

#ifndef BEEPTRIM_PITCH_RATE_DEGPS
#define BEEPTRIM_PITCH_RATE_DEGPS                   0.2f
#endif

allows the user to define the value of the macro using the command line argument (in gcc/clang/VS) -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f.

There is another important reason. It is an error to re-define a preprocessor macro differently. See this answer to another SO question. Without the #ifndef check, the compiler should produce an error if -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f is used as a command line argument in the compiler invocation.