重点:
- 多文件编译与链接过程
- 宏定义&
MAKE
文件 - 程序命令行参数
- GDB调试工具
声明与定义
对于头文件,尽量只申明函数而不实现函数。尽量只声明全局变量而不定义全局变量
声明:告诉编译器关于变量名称、变量类型、变量大小,函数名称、结构名称大小等信息,在此阶段不会给变量分配任何的库存。
- 声明变量:
extern int x;
;也可以用于函数声明 - 通常用在全局变量在不同文件内的共享
- 头文件中只是进行函数声明,并没有实现(定义)函数体,避免在链接时发现多个相同的函数实现(重复定义)而发生错误
- 声明变量:
定义:变量声明+内存分配
- 我们常见的
int x=1
或者int x
都是变量定义,后者只是缺少初始化
- 我们常见的
宏定义
#define
:一种预编译指令,用于给一个字符串定义一个“标识符”,这个标识符叫做宏名,被定义的字符串叫做替换文本;- 预编译:宏替换:将宏名用被定义的字符串替换后再进行编译
- 作用域:宏定义的有效范围称为宏名的作用域,宏名的作用域从宏定义的结束处开始到其所在的源代码文件末尾,不受分程序结构的影响。
- 可以用预处理指令
#undef
加上宏名终止宏名的作用域。
- 可以用预处理指令
- 宏定义的简单使用:<宏名>(<参数表>) <字符串>
1
2#define PI 3.14
#define sqrt(x) ((x)*(x))- 常量常用const定义
- 注意line2在去掉字符串中x的括号时会引起运算错误:如果用
sqrt(u+v)
会输出u+v*u+v
,由此体现宏替换只是简单的替换,并不会作出任何改变;如果有语法错误也只能在编译阶段发现
- 宏使用时的其他指令
- 避免头文件重复包含
#pragma
指令:可以设置面一起状态或者指示编译器进行特定活动:- #pragma once:保证头文件只被编译一次。
- #pragma message(“info”),在编译信息输出窗口中输出相应的信息,例如
#pragma message("Hello")
。 - #pragma warning,设置编译器处理编译警告信息的方式,例如
#pragma warning(disable:4507 34;once : 4385;error:164)
等价于#pragma warning(disable:4507 34)
(不显示4507和34号警告信息)、#pragma warning(once:4385)
(4385号警告信息仅报告一次)、#pragma warning(error:164)
(把164号警告信息作为一个错误)。
1
2
3
4
5
6
7
8
9#ifndef name //=if !def
#define newName
#else
//程序段
#endif
// or
#pragma once //保证物理上的同一个文件不会被编译多次- 用于debug输出,控制程序是否输出调试信息
1
2
3
4// #define DEBUG
#ifdef DEBUG
count<<"val:<<val<<endl;
#endif #error
:指令使预处理器发出一条错误消息,然后停止执行预处理。1
2#error info
#error MFC requires C++ compilation
- 避免头文件重复包含
编译与连接
过程
- 预处理:根据预处理指令对代码源文件处理,比如宏替换
- 编译:检查语法
- 第一遍执行语法分析与静态类型检查,把源代码解析为语法分析树的结构
- 第二遍由代码生成器遍历语法分析树,把树的每个节点转换为汇编语言或机器代码,生成目标模块
.o
或.obj
文件
- 汇编:汇编代码转换机器码,可以利用反汇编调试代码
- 链接:将各目标文件中的各段代码进行地址定位,从而把一组目标模块链接为可执行程序,使操作系统可以执行它;处理目标模块中的函数或变量引用,必要时搜索库文件处理所有的引用。
- 如果有外部函数声明但是没有函数实现,无法通过链接,但是可以通过编译
编译指令
g++ -c
:只编译不链接g++ -o ex1.out ex1.o
:链接程序g++ ex5_main.cpp func.cpp -o
:直接编译
MAKE
工具
通过写入MakeFile
文件可以实现