zhouqijie

序 C++多文件结构和编译预处理命令



C++编译过程

※在一个较大的项目中往往有多个源程序文件,每个源程序文件称为一个编译单元。这时C++语法要求每一个类的定义(声明)必须出现在所有使用这个类的编译单元中。惯用的做法是将类的声明写在头文件中。
※通常一个项目至少划分为三个文件:类声明文件(.h)、类实现文件(.cpp)、类使用文件(.cpp,主函数文件)。对于更复杂的程序,每一个类都有单独的声明和实现文件。



库文件及其头文件

(From CNBLOG) 简单的说:库文件提供定义/实现,其头文件提供声明。

C 代码的编译过程: 预处理(需要头文件) -> 编译 -> 汇编 -> 链接(需要库文件); 执行时可能还有动态链接过程。

在早期的编程语言中Basic Fortan没有头文件的概念,c++/c语言的初学者虽然会使用头文件,但是常常不明其理。

1、通过头文件来调用库功能。 在很多场合,源代码不便(或不准)向用户公布, 只要向用户提供头文件和二进制的库即可,用户只需要按照头文件中的接口声明来调用库函数, 而不必关心接口是怎么实现的,编译器会从库中提取相应的代码; 2、头文件能加强类型安全检查, 某个 接口被实现或被使用时的方式如果与头文件的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改错的负担; 3、头文件可以提高程序的可读性;

一、编译预处理



包含指令(#include)

预处理指令#include(两种书写方式):(include等同于文件拼接)

1、#include<>:按照标准方式搜索要嵌入的文件,该文件位于编译环境的include子目录下,一般用于嵌入系统提供的标准文件。比如标准头文件iostream。
2、#include “
.h”:表示首先在当前目录下搜索要嵌入的文件,如果没有,再按照标准方式搜索。

头文件包含原理:

头文件不建议include其他。include尽量写到cpp文件里。

头文件重复包含:

可以用#pragma once让头文件只被编译一次。

头文件交叉包含:

头文件被其他cpp文件包含:

注意事项:

在头文件类声明中声明指针成员不需要依赖指针所指类型,因为指针只是一个固定整型变量。



宏定义指令(#define和#undef)

——-宏——-

★计算机科学里的宏是一种抽象的,根据一系列预定义的规则替换一定的文本模式。解释器或编译器在遇到宏时会自动进行这一模式替换。对于编译语言,宏展开在编译时发生,进行宏展开的工具常被称为宏展开器。

—–宏定义——

★一个标识符被宏定义后,该标识符便是一个宏名。这时,在程序中出现的是宏名,在该程序被编译前,先将宏名用被定义的字符串替换,这称为宏替换,替换后才进行编译,宏替换是简单的替换。

—–#define指令——

1、在C/C++中可以用于定义符号常量。(在C++中通常用const关键字)
2、可以定义带参数宏。(例如#define Sqr(x) x*x)
3、可以定义空符号。(定义它的目的仅仅是表示它已经定义过,通常配合条件编译指令一起使用,起到某些特殊作用)

——#undef指令——-

★删除由#define定义的宏,使之不再起作用。



条件编译指令

※使用条件编译指令,可以限定程序中的某些内容要在一定条件下才能参与编译。

—–#if / #elif / #else / #endif用法——–

#if 表达式
    程序段
#endif

—–#ifdef / #else / #endif用法——–

#ifdef 标识符
    程序段
#endif



补充:defined操作符:

★这是一个操作符,不是指令。
★用法:当某标识符定义过则”defined(标识符)”表达式的值为非0,否则表达式值为0。
★”#ifdef 标识符”等同于”#if defined(标识符)”。





外部变量/外部函数/标准库



外部变量和外部函数

(源文件如果要共用全局变量,使用extern关键字。)

※如果一个变量除了在定义它的源文件中可以使用外,还能被其他文件使用,那么就称它为外部变量。在其他文件中如果要使用它则须用extern 类型 变量名先声明。(引用性声明)(对应的是定义性声明)

※命名空间作用域中定义的变量和函数,默认情况下都都是外部的,可以被其他编译单元访问。

※如果不想让变量、函数暴露给其他编译单元。可以用namespace{...}匿名命名空间。(曾经是用static关键字)



标准C++库

★在C语言中,系统函数,系统的外部变量和一些宏定义都是放置在运行库中。C++的库中除了保留了大部分C语言系统函数外,还加入了预定义的模板和类。标准C++库是一个极为灵活可扩展的可重用软件模块的集合。

———标准C++类和组件的6种类型———

1、输入输出类;
2、容器类和ADT(抽象数据类型);
3、存储管理类;
4、算法;
5、错误处理;
6、运行环境支持;

—————–引入命名空间——————-

★格式:using namespace 命名空间名
★如果不引入命名空间,要使用命名空间中标识就必须加上命名空间名和和域操作符,格式”命名空间名::标识符”。