是否在宏扩展之前处理#include指令,无论它们在文件中的位置如何? [英] Are #include directives processed prior to macro expansion regardless of their location within a file?
问题描述
前几天,我遇到了一些类似于以下内容的代码(为简洁起见,以下代码已过分简化):
I came across some code the other day that was similar to the following (the following has been over-simplified for the sake of brevity):
config.h
#ifndef __CONFIG__
#define __CONFIG__
#define DEVELOPMENT_BLD _TRUE_
#if (DEVELOPMENT_BLD == _TRUE_)
#define FILE_EXT ".dev"
#else
#define FILE_EXT ".bin"
#endif
#define PROJECT_STRING "my_project"
#define FILE_NAME PROJECT_STRING FILE_EXT
/* Common include files */
#include "my_defs.h"
#endif /* __CONFIG__ */
my_defs .h
#ifndef __MY_DEFS__
#define __MY_DEFS__
#define _TRUE_ 1
#endif /* __MY_DEFS__ */
编译时没有任何问题,但是由于我做了一些小改动(并且实际项目相当大),所以我决定在上面运行Lint。当我这样做时,我收到以下错误:
The project had always compiled without any issues, but since I made some minor changes (and the actual project was rather large) I decided to run Lint on it. When I did, I received the following error:
警告553:未定义的预处理变量'_TRUE_',假定为0
然后我想知道为什么编译器没有捕获到my_defs.h中定义的 _TRUE _
,强烈使用宏之后。因此,我在具有相同结果的其他编译器上进行了编译-成功编译,没有任何警告,并且无论我如何设置 DEVELOPMENT_BLD都正确评估了
(使用 FILE_NAME
_TRUE _
或!_ TRUE _
)。这是我的两个编译器设置:
I then wondered why the compiler didn't catch that _TRUE_
is defined in my_defs.h which is included after the macro's first usage. So I compiled it on a different compiler with the same results - succesful compilation, no warnings and FILE_NAME
was correctly evaluated regardless of how I set DEVELOPMENT_BLD
(using _TRUE_
or !_TRUE_
). Here are my two compiler settings:
ArmCC -c -cpu Cortex-M3 -g -O0 --apcs = interwork -I .. \ARM\CMSIS\Include -I ..\ARM\INC\NXP\LPC17xx -o file.o --omf_browse file.crf --depend file.d file.c
mingw32-gcc.exe -pedantic -Wall -g -c D:\ \dev\practice\header_question\main.c -o obj\Debug\main.o
我决定运行一个简单的测试,以查看预处理器是否正确评估了 FILE_NAME
的值。我还想查看 DEVELOPMENT_BLD
的实际值。我两次运行以下代码:
I decided to run a simple test to see if the value of FILE_NAME
was being properly evaluated by the preprocessor. I also wanted to see what the value of DEVELOPMENT_BLD
actually was. I ran the following code two times:
main.c
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("FILE_NAME:%s, WHAT_IS_TRUE:%d", FILE_NAME,DEVELOPMENT_BLD);
return 0;
}
我第一次使用值 #define DEVELOPMENT_BLD _TRUE _
结果如下:
The first time I used the value #define DEVELOPMENT_BLD _TRUE_
with this result:
FILE_NAME:my_project.dev,WHAT_IS_TRUE:1
第二次使用值 #define DEVELOPMENT_BLD!_TRUE _
,结果如下:
The second time I used the value #define DEVELOPMENT_BLD !_TRUE_
with this result:
FILE_NAME:my_project.bin,WHAT_IS_TRUE:0
我的第一个想法是也许 _TRUE _
是在其他地方定义的-因此请确保我已注释掉 #include my_defs.h
。然后,我开始收到编译器错误:
My first thought was that perhaps _TRUE_
was being defined elsewhere - so just to be sure I commented out #include "my_defs.h"
. I then began to receive a compiler error:
错误:未声明 _TRUE _(此功能首次使用)
所有这些都引起了我的疑问。
All of that leads to my question. Are #include statements required to be evaluated by the preprocessor before macro expansion or did I just get lucky?
推荐答案
C pre-是在宏扩展之前需要由预处理程序对#include语句进行评估吗?处理器在遇到指令时就对其执行操作。在这种情况下,警告是正确的;在使用 #if DEVELOPMENT_BUILD == _TRUE _
时, _TRUE _
的有效值为零。但是,由于 #define DEVELOPMENT_BUILD _TRUE _
的定义,预处理程序正在评估 #if 0 == 0
,即真正。但是,如果指定 #define DEVELOPMENT_BUILD _FALSE _
,您将得到相同的结果,因为 _FALSE _
也将是隐式为0,因此测试将再次为 #if 0 == 0
(其结果也为true)。如果预处理器在 #if
条件下完成对表达式的求值后,还有剩余的标识符,则隐式假定它们为0。
The C pre-processor acts on directives as it encounters them. In this context, the warning is correct; at the time you use #if DEVELOPMENT_BUILD == _TRUE_
, the effective value of _TRUE_
is zero. However, because of the #define DEVELOPMENT_BUILD _TRUE_
definition, the preprocessor is evaluating #if 0 == 0
, which is true. However, you'd have had the same result if you'd specified #define DEVELOPMENT_BUILD _FALSE_
because _FALSE_
would also be implicitly 0 and hence the test would be #if 0 == 0
again (which also evaluates to true). If, when the preprocessor has finished evaluating expressions in the #if
condition, there are identifiers left over, they are implicitly assumed to be 0.
请注意,以下划线和大写字母开头或其他下划线开头的名称保留给实现使用。您选择了诸如 _TRUE _
和 __ CONFIG __
之类的名字,步履蹒跚。 (只是因为系统标头使用这样的名称并不是您这样做的充分理由—实际上,情况恰恰相反。系统标头要谨慎地保留在保留供您使用的名称空间之外;您应该在名称空间之外为系统保留。)
Note that names starting with an underscore and a capital letter or another underscore are reserved for any use by the implementation. You are treading on very thin ice with your choic of names such as _TRUE_
and __CONFIG__
. (Just because system headers use names like that is not a good reason for you to do so — in fact, quite the opposite. The system headers are carefully keeping out of the namespace reserved for you to use; you should keep out of the namespace reserved for the system.)
这篇关于是否在宏扩展之前处理#include指令,无论它们在文件中的位置如何?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!