c语言标头字符,C语言标头包括警卫队

本文介绍了在C编程中防止头文件重复包含的重要性,通过使用include防护习惯用法(如 ifndef 宏)来避免编译错误。讨论了结构体的不透明声明以及typedef的使用,还提到了#pragma once的非标准但常见做法,强调了保持头文件保护的独特性和代码可移植性的平衡。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

示例

几乎每个头文件都应遵循include防护习惯用法:

我的头文件

#ifndef MY_HEADER_FILE_H

#define MY_HEADER_FILE_H

// 头文件的代码体

#endif

这样可以确保当您#include "my-header-file.h"在多个位置时,不会得到函数,变量等的重复声明。请想象以下文件层次结构:

头文件1.h

typedef struct {

} MyStruct;

int myFunction(MyStruct *value);

标头2.h

#include "header-1.h"

int myFunction2(MyStruct *value);

main.c

#include "header-1.h"

#include "header-2.h"

int main() {

// 做点什么

}

此代码有一个严重的问题:的详细内容MyStruct定义了两次,这是不允许的。由于一个头文件包含另一个头文件,因此这将导致难以跟踪的编译错误。如果您改为使用标头后卫进行操作:

头文件1.h

#ifndef HEADER_1_H

#define HEADER_1_H

typedef struct {

} MyStruct;

int myFunction(MyStruct *value);

#endif

标头2.h

#ifndef HEADER_2_H

#define HEADER_2_H

#include "header-1.h"

int myFunction2(MyStruct *value);

#endif

main.c

#include "header-1.h"

#include "header-2.h"

int main() {

// 做点什么

}

然后将其扩展为:

#ifndef HEADER_1_H

#define HEADER_1_H

typedef struct {

} MyStruct;

int myFunction(MyStruct *value);

#endif

#ifndef HEADER_2_H

#define HEADER_2_H

#ifndef HEADER_1_H // 安全,因为HEADER_1_H是之前#define的。

#define HEADER_1_H

typedef struct {

} MyStruct;

int myFunction(MyStruct *value);

#endif

int myFunction2(MyStruct *value);

#endif

int main() {

// 做点什么

}

当编译器到达header-1.h的第二个包含时,HEADER_1_H先前的包含已经定义了它。因此,归结为以下几点:

#define HEADER_1_H

typedef struct {

} MyStruct;

int myFunction(MyStruct *value);

#define HEADER_2_H

int myFunction2(MyStruct *value);

int main() {

// 做点什么

}

因此,没有编译错误。

注意:命名头保护器有多种不同的约定。有些人喜欢命名HEADER_2_H_,有些包括项目名称MY_PROJECT_HEADER_2_H。重要的是要确保遵循的约定使项目中的每个文件都有唯一的头保护。

如果标头中未包含结构详细信息,则声明的类型将为不完整或不透明的类型。此类类型很有用,可以向函数用户隐藏实现细节。在许多方面,FILE标准C库中的类型可以视为不透明类型(尽管它通常不是不透明的,因此标准I / O函数的宏实现可以利用结构的内部结构)。在这种情况下,header-1.h可能包含:

#ifndef HEADER_1_H

#define HEADER_1_H

typedef struct MyStruct MyStruct;

int myFunction(MyStruct *value);

#endif

请注意,该结构必须具有标签名称(在这里MyStruct-位于标签名称空间中,与typedef name的普通标识符名称空间分开MyStruct),并且{ … }省略。这说“有一个结构类型,struct MyStruct并且有一个别名MyStruct”。

在实现文件中,可以定义结构的详细信息以使类型完整:

struct MyStruct {

};

如果使用的是C11,则可以重复typedef struct MyStruct MyStruct;声明而不会导致编译错误,但是C的早期版本会抱怨。因此,即使在此示例中,如果代码仅使用支持C11的编译器进行编译,它仍然是可选的,即使在此示例中,它仍然是最佳选择。

许多编译器支持#pragma once伪指令,其结果相同:

我的头文件

#pragma once

// 头文件代码

但是,#pragma once它不是C标准的一部分,因此如果使用它,则代码的可移植性较差。

一些标头不使用include防护习惯用法。一个特定的例子是标准头。它可以多次包含在一个转换单元中,这样做的效果取决于NDEBUG每次包含标头时是否都定义了宏。您可能偶尔会有类似的要求;这样的情况很少。通常,您的标头应使用include Guard惯用语进行保护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值