版权声明:未经作者允许,严禁用于商业出版,否则追究法律责任。转载请注明出处!!!
1 防止头文件重复引入
使用预编译指令,常用的预编译指令如下:
//条件编译
#define // 宏定义
#undef // 取消宏
#include // 文本包含
#ifdef // 如果宏被定义就进行编译
#if defined // 与ifdefine的区别在于可以可以组成复杂的判别条件
#ifndef // 如果宏未被定义就进行编译
#if !defined // 与if !define的区别在于可以可以组成复杂的判别条件
#endif // 结束编译块的控制
#if defined // 表达式非零就对代码进行编译
#else // 作为其他预处理的剩余选项进行编译
#elif // 这是一种#else和#if的组合选项
#elif defined // 与ifdefine的区别在于可以可以组成复杂的判别条件
#elif !defined // 与ifdefine的区别在于可以可以组成复杂的判别条件
//编译指令
#line // 改变当前的行数和文件名称
#error // 输出一个错误信息
#pragma // 为编译程序提供非常规的控制流信息,可跟once,message等许多参数。
注:这里针对的都是在一个
.c
文件中避免头文件重复引入。如果一个工程有多个".c"文件,由于编译器对每个.c
文件是分开处理的,只在最后进行链接。在这种情况下,如果有多个.c
文件都直接或间接引入了某个头文件,这时无法避开的。
1.1 使用条件编译指令
头文件的里内容都包含在条件指令中:
#ifndef XXXX_H
#define XXXX_H
......
......
#endif
优点:
- 不光可以保证同一个文件不被包含多次,也能保证内容完全相同的两个文件(或者代码片段)不被同时引入。
- 受C/C++语言标准的支持,不受编译器的任何限制
缺点:
- 如果不同头文件中的宏名不小心“撞车”,可能就会导致你看到头文件明明存在,编译器却硬说找不到声明的状况——这种情况有时非常让人抓狂。
- 由于编译器每次都需要打开头文件才能判定是否有重复定义,因此在编译大型项目时,条件编译指令会使得编译时间相对较长,因此一些编译器逐渐开始支持
#pragma once
的方式。
1.2 使用pragma once指令
pragma once
编译指令使得同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。你无法对一个头文件中的一段代码作pragma once声明,而只能针对文件。
优点:
-
你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。
-
遇到已经引入过的头文件时会直接跳过,而不需要打开。因此大型项目的编译速度也因此提高了一些。
缺点:
-
#pragma once
方式却不受一些较老版本的编译器支持,一些支持了的编译器又打算去掉它,所以它的兼容性可能不够好。 -
如果某个头文件有多份拷贝或者被多个
.c
或.h
文件引入,pragma once
不能保证他们不被重复引入。当然,相比宏名碰撞引发的“找不到声明”的问题,这种重复包含很容易被发现并修正。
1.3 两者混用
两者混用可以节约一定的间,比如多次引入同一“物理意义上的”头文件,就可以不用展重复引入开头文件。
#pragma once
#ifndef XXXX_H
#define XXXX_H
……
……
#endif
2 防止重复定义
最根本的方式是将声明和定义分开。
在.c
文件中定义,在*.h
中声明。声明包括函数声明,自定义数据类型声明,外部变量声明等。如:
//test.c
#include"add.h" //头文件应全部在对应的*.h中引入,`*.c`文件只需引入对应的`*.h`文件即可
int c[10]={0};
int Add(int a, int b)
{
return a+b;
}
//test.h
#pragma once
#ifndef TEST_H
#define TEST_H
extern int c[];
int Add(int a, int b);
#endif
//main.c
#include"test.h"
int main()
{
return add(c[0],1);
}
如果一定要把定义放在头文件中,则该工程中只能有一个.c
文件中可以先定义对应宏,再直接或间接引入该头文件。格式如下:
//一个工程有多个.c文件
//comm.h,定义放在头文件中
#pragma once
#ifndef COMM_H
#define COMM_H
#ifdef EXTERN_C
int c=10;
#else
extern int c;
#endif
#endif
//addc.h,
#pragma once
#ifndef ADDC_H
#define ADDC_H
#include"comm.h"
int addc(int ,int);
#endif
//addc.c
#define EXTERN_C //只能有一个.c文件中可以先定义对应宏,再直接或间接引入该头文件
#include"addc.h"
int addc(int a, int b)
{
return a+b+c;
}
//subc.h
#pragma once
#ifndef SUBC_H
#define SUBC_H
#include"comm.h"
int subc(int ,int);
#endif
//subc.c
#include"sub.h"
int subc(int a, int b)
{
return a-b-c;
}
//main.c
#include"add.h"
#include"sub.h"
int main()
{
addc(1,2);
subc(1,2);
}
......
版权声明:未经作者允许,严禁用于商业出版,否则追究法律责任。转载请注明出处!!!