0%

内存模型

头文件通常包含的内容

  • 函数原型
  • 使用了#define或const定义的符号常量
  • 结构声明
  • 类声明
  • 模板声明
  • 内联函数
    用#include “”率先在当前工作目录或者源代码目录下找
    用#include <>率先在标准头的目录下找

同一个头文件只包含一次

1
2
3
4
#ifndef INCLUDE_H_
#define INCLUDE_H_
...
#endif

多个库的链接

需要确保对象文件或库都是由同一个编译器生成的,若不同的编译器,会为同一个函数生成不同的修饰名称。若有源代码建议用自己的编译器全部重新编译,以消除链接错误。

存储数据的三种方案

  • 自动存储持续性:函数中声明的变量以及函数参数,会在执行中自动创建,执行完自动释放
  • 静态存储持续性:使用static关键字的变量,在整个程序运行过程均存在
  • 动态存储持续性:用new分配的内存,一直存在直到delete

编译器把自动变量用堆栈的形式管理

register的变量放在寄存器,依然没有链接性

静态存储提供三种链接性

  • 外部链接性:全局(外部链接性)变量(main函数外)
  • 内部链接性:static的全局变量
  • 无链接性: 内部的static变量
    静态变量持续整个程序执行期间,编译器将分配固定的内存块来管理。默认情况下,静态数组以及结构的成员都设置为0。

外部链接性使用

1
2
3
4
5
6
7
8
9
10
11
12
// file1
int status = 100;
#include "file2.hpp"
print();

// file2
extern int status;
void print()
{
cout << status;
}

如果file2中,用status int status或者 extern int status=20;都会报重新定义的错误。

应使用外部变量在多文件程序的不同部分共享数据

内部链接性的静态变量用于多个函数之间共享数据(名称空间提供了新的共享数据方法,static的内部链接性逐步淘汰)

存储说明符:auto, register, static, extern, mutable

auto为自动变量;register为寄存器存储;static在整个cpp文件的声明具有函数间的链接性;extern是多文件的外部链接性;mutable使const临时失效;
volatile指程序代码没有对内存单元修改,其值也可能发生变化。即每次使用该变量都应其查找,别用缓存。

另外

1
const int fingers = 10; //same as static const int fingers;

const使全局变量变成了内部链接性。

但是在另外的文件用 extern const int fingers;又可以强行变成外部链接性而可用。

关于函数的链接性

由于C++不允许函数中定义另外的函数,所以所有函数都为静态存储持续性。但依然可以用extern来使函数为另一个文件使用。使用该函数的每个文件应包含函数原型(方便了解接口的描述,内联函数可以无需接口描述)

语言链接性

由于C和C++编译器对函数翻译不一致,在调用C外部链接函数时,应该标注extern “C”

1
2
e.g.
extern "C" void spiff(int);

布局new占位符

1
2
3
4
const int BUF = 512;
char buffer[BUF];
double *pd1 = new double[BUF];
double *pd2 = new (buffer)double[BUF];

上述两个指针,pd2为交由程序员自身管理的动态内存;且pd2在delete管辖区域之外。

命名空间及前途

  • 命名空间具有外部链接性
  • 使用在已命名的名称空间中声明的变量,而不是使用外部全局变量
  • 使用在已命名的名称空间中声明的变量,而不是使用静态全局变量
  • 如果开发函数库或者类库,将其放入一个名称空间中。如当前C++提倡标准库的都放入std空间中
  • 不要在头文件使用using,这样会掩盖了可用的名称;另外包含头的顺序会影响程序的行为;若坚持则应在所有的#include后用
  • 导入名称时,首选用作用域解析或using声明
  • 对于using声明,首选将作用域于局部,而非全局

命名空间可以是全局的,也可以位于另一个名称空间中,但不能位于代码块中

using namespace std;就是using编译指令,使整个名称空间可用。