3

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

配置文件

#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。当我这样做时,我收到以下错误:

Warning 553: Undefined preprocessor variable '_TRUE_', assumed 0

然后我想知道为什么编译器没有捕获_TRUE_my_defs.h 中定义的内容,该文件包含宏第一次使用之后。所以我在不同的编译器上编译了它,结果相同——编译成功,没有警告,并且FILE_NAME无论我如何设置DEVELOPMENT_BLD(使用_TRUE_or !_TRUE_)都得到了正确的评估。这是我的两个编译器设置:

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。我运行了以下代码两次:

主程序

#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_这个结果的值:

FILE_NAME:my_project.dev, WHAT_IS_TRUE:1

我第二次使用#define DEVELOPMENT_BLD !_TRUE_这个结果的值:

FILE_NAME:my_project.bin, WHAT_IS_TRUE:0

我的第一个想法是,这可能_TRUE_是在其他地方定义的——所以只是为了确保我注释掉了#include "my_defs.h"。然后我开始收到编译器错误:

error: '_TRUE_' undeclared (first use in this function)

所有这些都引出了我的问题。#include 语句是否需要在宏扩展之前由预处理器评估,还是我只是幸运?

4

1 回答 1

4

C 预处理器在遇到指令时对其进行操作。在这种情况下,警告是正确的;在您使用#if DEVELOPMENT_BUILD == _TRUE_时, 的有效值_TRUE_为零。但是,由于#define DEVELOPMENT_BUILD _TRUE_定义,预处理器正在评估#if 0 == 0,这是真的。但是,如果您指定了#define DEVELOPMENT_BUILD _FALSE_因为_FALSE_也将隐含为 0,那么您将获得相同的结果,因此测试将#if 0 == 0再次出现(其计算结果也为真)。如果,当预处理器完成对条件中的表达式求值#if时,还有剩余的标识符,则它们被隐式假定为 0。

请注意,以下划线和大写字母或另一个下划线开头的名称保留供实现使用。_TRUE_选择和之类的名称,您是在履薄冰__CONFIG__上 (仅仅因为系统标头使用这样的名称并不是您这样做的好理由 - 事实上,恰恰相反。系统标头小心地远离保留供您使用的名称空间;您应该远离名称空间为系统保留。)

于 2013-05-15T23:09:47.370 回答