是否在宏扩展之前处理#include指令,无论它们在文件中的位置如何? [英] Are #include directives processed prior to macro expansion regardless of their location within a file?

查看:97
本文介绍了是否在宏扩展之前处理#include指令,无论它们在文件中的位置如何?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前几天,我遇到了一些类似于以下内容的代码(为简洁起见,以下代码已过分简化):

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆