C/C++#include 机制简述

1.引言

做c/c++编程的对#include指令都不会陌生,绝大多数也都知道如何使用,但我相信仍有人对此是一知半解,

C:

#include

C++:

#include

表示包含C/C++标准输入头文件。包含指令不仅仅限于.h头文件,可以包含任何编译器能识别的C/C++代码文件,包括.c,.hpp,.cpp,.hxx,.cxx等,甚至.txt,.abc等等都可以

2.名词解释

preprocess

预处理:为方便编译器处理而设置的一种机制,包括一些常用预处理指令和语句,我们统称为预处理系统。

如#include #define #if...#else...#endif #pragma等

这些指令的实现是由编译器来决定的(implementation specified)

提到预处理指令,顺便说一下头文件防止重复包含的2种方法

a.保护宏(暂且称为Macro guard 宏卫兵?):

#ifndef _ABCDE_H

#define _ABCDE_H

/*

代码部分

*/

#endif

在被包含过一次之后,宏_ABCDE_H已经有了,下次再碰到就会略过从#define _ABCDE_H开始到#endif之间的代码

还有一种特定编译器支持的指令:

b.#pragma once

能保证该文件(物理上的)只被编译一次,也能起到防止重复包含的作用

但这2种方式是有区别的:

a.Macro guard可移植性好,绝大多数编译器都支持,而且万一不小心拷贝了几分相同的代码也不会出问题,但你得确保这个宏名不会与其他的宏冲突,否则等编译器报出一大堆错误的时候你可能会觉得莫名其妙;

b.#pragma once指令简单,它能保证该文件(物理上的)只被编译一次,不用去费劲的想不同的宏名,但如果有几份该文件的拷贝,显然起不到作用。

declaration

声明:指将一个名称引入当前编译单元,或者重新声明一个前面已经声明过的名称,声明指定了如何解释一个名称和该名称具有的属性;

例如:

int main(void)

{

int a;  // 声明了变量a,类型为int

int *pa; // 声明了变量pa,类型为指向int型的指针类型

}

definition

定义:除了以下情况,声明就是定义

a.声明函数但不包括函数体;

b.声明包含extern链接限定符,例如:extern int a;

c.声明既没有初始化语法,也没有函数体;

d.类声明中声明静态数据成员;

e.类名字声明;

f.typedef声明;

g.using声明或者using指令;

以上情况适用于C具有的特征,C++则完全适用,一般来说定义要为其对象分配或预留存储空间,而声明则不用。

translation unit

编译单元:一个源文件,.c .cpp等和它所包含的文件一起,在经过预处理之后形成一个源码文件,标准称之为translation unit(编译单元)包括一系列的声明和定义;一个program(程序)由一个或多个编译单元组成。编译器将各个翻译单元编译为目标代码(.obj),通过连接器(linker)将这些编译后的编译单元(即目标代码)连接成完整的指令序列(可执行文件、静态库、动态库等)。

one definition rule

一次定义规则:是指定义在所有进入连接的编译单元中只能有一次。

3.观点、例子

A:头文件只放声明

example_a.h

void function();

example_a.cpp:

#include "example_a.h"

void function()

{}

B.被包含的文件可以使用任意扩展名:

只要是用符合标准的代码编写的文本文件,就可以使用#include来进行包含,包括.cpp .c等常见的源文件扩展名;

example_b_1.b

void function();

example_b_1.cpp:

#include "example_b_1.b"

void function()

{}

example_b_2.b

void function1();

void function2();

example_b_21.cpp:

void function1()

{}

example_b_22.cpp:

#include "example_b_1.b"

#include "example_b_21.cpp"

void function2()

{}

上面的例子中,example_b_21.cpp仅被包含在xample_b_22.cpp中,不再被其他的文件包含,而且不加入工程中;

C.标准头文件的使用

最新的C++标准库中的一切内容都被放在名字空间std中(名字空间中的内容对外是不可见的),但是带来了一个新问题,无数现有的C++代码都依赖于使用了多年的伪标准库中的功能,如声明在等头文件中的功能,使用std包装标准库导致现有代码的不可用,为了兼容这种情况,标准委员会为包装了std的那部分标准库创建了新的头文件,新的头文件的文件名与旧的一样,只是没有.h这个后缀,如就变成了。对于C头文件,采用同样的方法,但还在每个头文件名前加了字符c,如就变成了,变成了。最好使用新的文件头,使用新的文件头的C++程序,需要使用using namespace std或者using namespace std::指定的类名,等方法来使需要的类对于我们的代码可视。

4.总结

既然是经常使用的东西,我们就应该明白它的原理,减少编程时的困惑,提高编程的效率。

1.引言

做c/c++编程的对#include指令都不会陌生,绝大多数也都知道如何使用,但我相信仍有人对此是一知半解,

C:

#include

C++:

#include

表示包含C/C++标准输入头文件。包含指令不仅仅限于.h头文件,可以包含任何编译器能识别的C/C++代码文件,包括.c,.hpp,.cpp,.hxx,.cxx等,甚至.txt,.abc等等都可以

2.名词解释

preprocess

预处理:为方便编译器处理而设置的一种机制,包括一些常用预处理指令和语句,我们统称为预处理系统。

如#include #define #if...#else...#endif #pragma等

这些指令的实现是由编译器来决定的(implementation specified)

提到预处理指令,顺便说一下头文件防止重复包含的2种方法

a.保护宏(暂且称为Macro guard 宏卫兵?):

#ifndef _ABCDE_H

#define _ABCDE_H

/*

代码部分

*/

#endif

在被包含过一次之后,宏_ABCDE_H已经有了,下次再碰到就会略过从#define _ABCDE_H开始到#endif之间的代码

还有一种特定编译器支持的指令:

b.#pragma once

能保证该文件(物理上的)只被编译一次,也能起到防止重复包含的作用

但这2种方式是有区别的:

a.Macro guard可移植性好,绝大多数编译器都支持,而且万一不小心拷贝了几分相同的代码也不会出问题,但你得确保这个宏名不会与其他的宏冲突,否则等编译器报出一大堆错误的时候你可能会觉得莫名其妙;

b.#pragma once指令简单,它能保证该文件(物理上的)只被编译一次,不用去费劲的想不同的宏名,但如果有几份该文件的拷贝,显然起不到作用。

declaration

声明:指将一个名称引入当前编译单元,或者重新声明一个前面已经声明过的名称,声明指定了如何解释一个名称和该名称具有的属性;

例如:

int main(void)

{

int a;  // 声明了变量a,类型为int

int *pa; // 声明了变量pa,类型为指向int型的指针类型

}

definition

定义:除了以下情况,声明就是定义

a.声明函数但不包括函数体;

b.声明包含extern链接限定符,例如:extern int a;

c.声明既没有初始化语法,也没有函数体;

d.类声明中声明静态数据成员;

e.类名字声明;

f.typedef声明;

g.using声明或者using指令;

以上情况适用于C具有的特征,C++则完全适用,一般来说定义要为其对象分配或预留存储空间,而声明则不用。

translation unit

编译单元:一个源文件,.c .cpp等和它所包含的文件一起,在经过预处理之后形成一个源码文件,标准称之为translation unit(编译单元)包括一系列的声明和定义;一个program(程序)由一个或多个编译单元组成。编译器将各个翻译单元编译为目标代码(.obj),通过连接器(linker)将这些编译后的编译单元(即目标代码)连接成完整的指令序列(可执行文件、静态库、动态库等)。

one definition rule

一次定义规则:是指定义在所有进入连接的编译单元中只能有一次。

3.观点、例子

A:头文件只放声明

example_a.h

void function();

example_a.cpp:

#include "example_a.h"

void function()

{}

B.被包含的文件可以使用任意扩展名:

只要是用符合标准的代码编写的文本文件,就可以使用#include来进行包含,包括.cpp .c等常见的源文件扩展名;

example_b_1.b

void function();

example_b_1.cpp:

#include "example_b_1.b"

void function()

{}

example_b_2.b

void function1();

void function2();

example_b_21.cpp:

void function1()

{}

example_b_22.cpp:

#include "example_b_1.b"

#include "example_b_21.cpp"

void function2()

{}

上面的例子中,example_b_21.cpp仅被包含在xample_b_22.cpp中,不再被其他的文件包含,而且不加入工程中;

C.标准头文件的使用

最新的C++标准库中的一切内容都被放在名字空间std中(名字空间中的内容对外是不可见的),但是带来了一个新问题,无数现有的C++代码都依赖于使用了多年的伪标准库中的功能,如声明在等头文件中的功能,使用std包装标准库导致现有代码的不可用,为了兼容这种情况,标准委员会为包装了std的那部分标准库创建了新的头文件,新的头文件的文件名与旧的一样,只是没有.h这个后缀,如就变成了。对于C头文件,采用同样的方法,但还在每个头文件名前加了字符c,如就变成了,变成了。最好使用新的文件头,使用新的文件头的C++程序,需要使用using namespace std或者using namespace std::指定的类名,等方法来使需要的类对于我们的代码可视。

4.总结

既然是经常使用的东西,我们就应该明白它的原理,减少编程时的困惑,提高编程的效率。


相关文章

  • 食品技术原理 1
  • 一.名词解释: 1.IQF means individual-quick-freezing.食品的各个单体在相对短的时间内裸露在低温介质中 2. FD is Freeze drying 升华干燥,是将含水物料冷冻到冰点以下,使水转变为冰,然 ...查看


  • 嵌入式软件工程师招考试题(linux)
  • 软件工程师招聘测试 考试时间:60分钟 总分:100分 1.有了malloc/free,为何还要new/delete?(5) 2.头文件中的 ifndef/define/endif 是用来做什么的?(5) 3.简述堆与栈的异同?(5) 4. ...查看


  • 软件公司入职面试笔试题(C++)
  • C++/C试题 本试题仅用于考查C++/C程序员的基本编程技能.内容限于C++/C常用语法,不涉及数据结构.算法以及深奥的语法.考试成绩能反映出考生的编程质量以及对C++/C的理解程度,但不能反映考生的智力和软件开发能力. 笔试时间90分钟 ...查看


  • iOS常见面试题总结
  • 1.objective-c常见面试题: 1.OC 语言的基本特点 OC 语言是 C 语言的一个超集,只是在 C 的基础之上加上了面向对象(oop) 的特性; OC 与 Java 语言相同都是单继承,这一点与 C++语言不同(多重继承); O ...查看


  • 2012年1月自考软件开发发工具试题真题及答案
  • 全国2012年1月高等教育自学考试 软件开发发工具试题 课程代码:03173 一.单项选择题(本大题共20小题,每小题1分,共20分) 在每小题列出的四个备选项中只有一个是符合题目要求的,请将其代码填写在题后的括号内.错选.多选或未选均无 ...查看


  • 各种实验报告电子版模版
  • 实验项目四 进程通信 一. 实验类型 本实验为综合性实验. 二. 实验目的 1. 了解什么是消息,熟悉消息传送原理. 2. 了解和熟悉共享存储机制. 3. 掌握消息的发送与接收的实现方法. 三. 实验预备知识 任务一 消息的发送和接收 1. ...查看


  • iOS求职之OC面试题
  • 1.Objective-C的类可以多重继承么?可以采用多个协议么? 答:不可以多重继承,可以采用多个协议. 2.#import和#include的区别是什么?#import 跟 #import""有什么区别? #impo ...查看


  • 多媒体课件制作
  • 期末作业考核 <多媒体课件制作> 满分100分 一.概念解释(每小题4分,共20分) 1.CAI 答.多媒体CAI 系统是一套复杂的计算机应用系统,主要由硬件平台.软件平台和课件三大部分构成.多媒体CAI 的教学功能由课件所决定 ...查看


  • linux c信号相关函数学习记录
  • 一.什么是信号    1. 信号就是软件中断,很多的程序都需要处理信号.信号提供了一种处理异步事件的机制. 例如:当用户在终端下运行一个程序时,用户在键盘键入一个中断键(CTRL+C),则会通过信号机制终止一个正在运行的程序. 2.每一个信 ...查看


热门内容