2020-C++高级程序设计-C++ Cpp
Cpp(编译预处理)
1. 编译预处理
- 与作用域、类型、接口等概念格格不入
- 潜伏于坏境:编译预处理,可以不写在程序中
- 穿透作用域:在编译预处理的时候,忽略作用域。
1 |
|
- 设想:
- 置换
- 应用方式丰富,很难为其的找到具有更好的结构且高效的替代品
- 关于对于#include、#define、#ifdef、#pragma的不同处理
2. #include
- include会打开文件内容,然后将文件内容拷贝过来
- 保证接口的定义在本文件中有效
- 暴露源文本
3. #define
3.1. 符号常量
#define pi 3.14
const pi = 3.14
- 不需要分号,因为他是编译预处理而不是代码
3.2. 开放子过程
使用inline函数
3.3. 过程函数泛型
#define max(a,b) (a) > (b) ? (a) : (b)
这个max宏和函数有什么区别- 为什么没有括号不行?因为他不懂乘法:
#define mul(a,b) a * b
- 如果使用:
max(1+2,2+3)//1 + 2 * 2 + 3
- 宏还可能带来重复计算(只是一个编译预处理)
- 为什么没有括号不行?因为他不懂乘法:
- double int等对函数重载
- 宏是定义和所有的同类型比较的泛型。
- 宏的严重缺陷,宏没有函数的类型检查
- 将int写成参数T(类型参数):
T max(T,T)
3.4. Generic types
- 使用模板来替代大量重复的部分
3.5. 重命名vaou
- namespace的形式
3.6. 字符串连接
- 不可以被替代
1 |
|
- 这个是为了帮助框架的实现
3.7. 特殊目的用法
- 不可以被替代
- 特殊语法:
1 |
|
- 例子:
1 |
|
- 有些程序的部分是保障机制,在不同形式下的保障是不同的
- 使用开关量的编译选择,用来在发布的时候对于不应该被发布的东西进行开关量的调整。(就可以不用删除)
- 有一些调试是不能通过断点调试的,所以我们就可以打开开关变量,用来记录更加清晰深刻的日志。
3.8. General macro processing
- 不可以被替代
- 我们可以将一些warning确认没有问题忽略掉
- 我们也可以通过将一些warning提高为error的高级别,这样子就可以更加清晰的发现问题(IDE集成)
1 |
|
4. #ifdef
- 版本控制
- 注释代码
5. #pragma
- 层间控制
- 告知编译器
#pragma pack()
- 在计算机内存空间中,我们往往是要进行数据的对齐,这样子可以提高内存数据的读取效率
- 我们可以通过传递预编译指令用来对于指定数据的对齐
- #pragma pack()用法详解
6. 程序组织
- 逻辑结构:相关联的函数/文件形成的抽象上的图结构
- 物理结构:考虑到每个函数f存储的位置,不一定存在同一个cpp
- 一个源程序不论有多少个源文件,只有一个源文件能包含main函数
- 工程文件
- 外部函数
- 外部变量
- 组织是物理层面
- 我们直接将一些头文件
.h
中写好函数原型
6.1. 头文件和cpp文件
- 我们要始终注意scope和lifetime
- 作用域
- 程序级作用域(函数外定义的变量):一个程序可能有很多源文件,程序级就是说整个程序可见
- 函数级作用域:在Stack中,同一个函数内可见
- 块级作用域:在Stack中,同一个代码块内可见,比如while循环中定义的一个变量
- 文件级作用域:在A和B中的process()是不同函数的,同一个文件中可见
- 协同:B中使用A中的,需要标明extern,然后在编译前确认查找
1 |
|
- 将外部要用的,开发的,A把对应的放到a.h头文件中,而B就不需要进行读取A文件内容,B在使用时在文件头
#include "a.h"
:功能就是直接复制粘贴过来,是preprocess命令 - 如果有些服务不想要提供:将作用域限制到文件内:就是文件级作用域
- 常量作用域默认是文件作用域,我们也将其抽象成为
const.h
文件来查看管理 - main是全生命周期的,活在栈中。
6.2. extern的另一个用法
- extern可以用来修饰变量或函数,用来说明此变量/函数是在别处定义的,要在此处引用,而不会新开辟一块内存。
- 该变量或函数必须是唯一的,如果多个cpp文件中都有定义则会报错
- 一般不用extern修饰常量,因为常量默认作用域是文件
- 函数默认的生命是extern的,带有关键字仅仅是语义上这个函数可能在其他源文件里有定义。
6.3. 头文件的内容
- 放置不占空间的部分
- 放置常量定义
- 放置变量/函数声明(为什么可以这么干?)
- a.cpp和a.h并没有联系,link时会从所有编译好的文件中找B需要的符号,如果几个不同文件中实现了同一个函数/定义了同一个全局变量,就会报错
- 编译阶段,B虽然找不到该函数或变量(理解为符号表的信息不完整),但连接时会从A生成的目标代码中找到此函数
- 放置宏
- 放置类型定义
- 放置内联函数(必须写到头文件)
- 为什么内联函数要放置到头文件中?因为不这么做,无法正常使用
- inline是基于源代码的复用,根据原型是不行的
- 如果头文件中有inline,但是被拒绝了?如果头文件中的inline函数很复杂(loop等),那么我们会将对应代码替换进去的时候,生成了多份的static(局部于文件作用域)
- 相对的话:如果不是inline函数,那么函数只会有一份。
1 |
|
- 头文件可以再次放置头文件
2020-C++高级程序设计-C++ Cpp
https://spricoder.github.io/2020/07/01/2020-C-plus-plus-advanced-programming/2020-C-plus-plus-advanced-programming-C++%20Cpp/