C包括警卫到底是做什么的



假设我有一个带有函数定义的头文件"header.h"。

#ifndef HEADER_FILE
#define HEADER_FILE
int two(void){
return 2;
}
#endif

此头文件具有包含保护。但是,我对 #define HEADER_FILE 实际上在做什么感到困惑。假设我忘记了包含保护,对我来说完全忽略添加"#define HEADER_FILE"是完全合法的。

当我们定义HEADER_FILE时,我们到底在做什么?我们在定义什么?为什么可以忘记包含保护,在这种情况下,我们也可以忘记添加 #define HEADER_FILE?

它是一个

预处理器宏。

所有这些都是预处理器语法,基本上是说,如果尚未定义此宏,请定义它并包含#ifndef#endif之间的所有代码

它完成的是防止多次包含文件,这可能会导致代码出现问题。

您的问题:

为什么可以忘记包含保护,在这种情况下,我们也可以忘记添加 #define HEADER_FILE?

忘记它是可以的,因为没有它它仍然是合法的 C 代码。预处理器在编译文件之前处理文件,如果没有逻辑指定为什么不应该,则在最终程序中包含指定的代码。这只是一种常见的做法,但不是必需的。

一个简单的例子可能有助于说明它是如何工作的:

header_file.h我们要说的是,您的头文件包含以下内容:

#ifndef HEADER_FILE
#define HEADER_FILE
int two(void){
    return 2;
}
#endif

在另一个文件 ( foo.c ) 中,您可能有:

#include "header_file.h"
void foo() {
    int value = two();
    printf("foo value=%dn", value);       
}

一旦它被"预处理"并准备好进行编译,这将转换为:

int two(void){
    return 2;
}
void foo() {
    int value = two();
    printf("foo value=%dn", value);       
}

包含保护在这里完成的所有工作是确定是否应粘贴#ifndef ...#endif之间的标头内容来代替原始#include

但是,由于该函数未声明externstatic,并且实际上是在头文件中实现的,因此如果您尝试在另一个源文件中使用它,则会遇到问题,因为函数定义将不包括在内。

您可以防止多次包含该文件,请点击此处

#ifndef HEADER_FILE

你测试是否HEADER_FILE没有定义,如果这是真的,那么

#define HEADER_FILE

会定义它,现在如果您将文件包含在另一个文件中,第一次它将定义 HEADER_FILE ,而第二次,它将已经定义,因此不再包含文件的内容,因为#ifndef HEADER_FILE将是假的。

请记住,这些在实际编译完成之前由预处理器进行评估,因此它们在编译时进行评估。

首先,在现代C++编译中,您可以使用#pragma once而不是包含保护。

然后,您的示例有点混乱,因为您在标头中定义了一个extern函数。通常include文件用于定义函数的声明,而不是函数的定义。

如果您在标头中定义函数,并且如果此标头被多个 CPP 源文件使用,则此函数将使用相同的名称定义更多次,并且在链接程序时会出现错误!

更好的包含将是

#ifndef HEADER_FILE
#define HEADER_FILE
int two(void);
#endif

#ifndef HEADER_FILE
#define HEADER_FILE
static int two(void) { return 2; }
#endif

#pragma once
static int two(void) { return 2; }

在最后一种情况下,函数two()在包含此标头的每个 CPP 源文件中定义;但是此函数是静态的,因此 CPP 源编译正确,并且 CPP 程序链接没有问题。

在你的问题中,你问

在这种情况下,我们也可以忘记添加 #define HEADER_FILE?

就个人而言,我在非常特殊棘手的情况下使用相同的标题。

以下 2 个包括一个"好"示例:

/*******************************************************************
* XTrace.Configuration.h
********************************************************************
*/
#pragma once
#define MODULEx(n) extern StructDefineMODULE MODULE_##n;
#include "XTrace.Modules.h"
#undef MODULEx
#define MODULEx(n) { #n, &MODULE_##n } ,
static struct ModuleTRACE tModuleTrace[]
= {
#include "XTrace.Modules.h"
  { 0, 0 }
  };

XTrace.Modules.h包含的位置如下

/*******************************************************************
* XTrace.Modules.h
********************************************************************
*/
MODULEx( BBDIXFILE )
MODULEx( CECHO )
MODULEx( INITDBFIELD )
MODULEx( IVIRLUX )

第一个包含包含 #pragma once 并调用相同的内部包含 2 次。

第一次调用它来定义 StructDefineMODULE 结构的外部声明。

第二次是调用初始化 ModuleTRACE 结构数组。

由于此包含被调用 2 次,因此必须避免#pragma once#ifndef

在使用内部包含时,我确信 100% 用于定义 StructDefineModule 的所有元素也用于初始化 tModuleTrace[] 数组。

包含内部结果,将是

/*******************************************************************
* XTrace.Configuration.h
********************************************************************
*/
#pragma once
extern StructDefineMODULE MODULE_BBDIXFILE;
extern StructDefineMODULE MODULE_CECHO;
extern StructDefineMODULE MODULE_INITDBFIELD;
extern StructDefineMODULE MODULE_IVIRLUX;
static struct ModuleTRACE tModuleTrace[]
= { { "BBDIXFILE"   , &MODULE_BBDIXFILE }
  , { "CECHO"       , &MODULE_CECHO }
  , { "INITDBFIELD" , &MODULE_INITDBFIELD }
  , { "IVIRLUX"     , &MODULE_IVIRLUX }
  , { 0, 0 }
  };

我希望这可以帮助您理解为什么在某些情况下可以避免包括警卫!

相关内容

  • 没有找到相关文章

最新更新