【C++Primer Chapter9】 内存模型和名称空间(1)

1. C++程序主要组成文件:

头文件:结构声明和使用这些结构的函数原型。

//NOTE1:头文件中不要包含变量声明和函数定义,因为链接阶段所有文件代码会结合成一个程序,一个程序中不能有多个函数定义(如果再多个源代码文件包含该头文件的话会问题的)

//NOTE2:头文件可包含内容:函数原型、结构声明、类声明、模板声明、内联函数、使用#define或const定义的符号常量。

源代码文件:结构有关的函数定义。

源代码文件(main):调用结构有关的函数的代码。

2. 文件名包含在尖括号<>中和双引号“”中的区别:

文件名包含在尖括号<>,则C++编译器将在存储标准头文件的主机系统的文件系统中查找,文件名包含在双引号“”中,则编译器首先会查找当前工作目录或源代码目录。

3.在同以文件中只能将同一个头文件包含一次,避免多次包含同一个头文件:

#ifndef FILENAME_H_
#define FILENAME_H_
...
#endif

4. 存储持续性、作用域和链接性:

存储持续性:根据用于分配内存的方法。C++分为3种管理数据内存的方法。存储类别关系到数据保留在内存中的时间和影响信息在文件间的共享。

作用域:描述名称在文件(翻译单元)在多大范围内可见(可用)。

链接性:名称如何在不同文件(翻译单元)之间共享。

不同的C++存储方式通过存储持续性、作用域和链接性来描述。

  •  自动存储持续性:

a. 自动变量(局部变量):自动存储,作用域为所定义的代码块内,无链接性(无法被其他代码块/文件使用)。在代码块中(可使用关键字 auto)声明。

//NOTE1:同名变量在子代码块内的新定义会隐藏以前的定义,使旧定义暂时不可见,在程序离开该代码块后,原定义又重新可见。

//NOTE2:存于堆栈中,新的声明的自动变量被压入栈中,代码块结束后该变量出栈。LIFO顺序。

b. 寄存器变量:自动存储,作用域为所定义的代码块内,无链接性。在代码块内使用关键字 register 声明。

//NOTE1:对于频繁使用的变量,程序使用关键字 register 向编译器申请使用CPU寄存器存储变量。在C语言中寄存器变量无法取址,C++中对此做了优化可以取址了(其实是c++编译器发现程序中需要取register关键字修饰的变量的地址时,register关键字的声明将变得无效。)

//NOTE2:c++编译器也有自己的优化方式,即某些变量不用register关键字进行修饰,编译器也会将多次连续使用的变量优化放入寄存器中,例如入for循环的循环变量i。

  • 静态存储持续性(静态变量):

编译器分配固定内存块来存储所有的静态变量。这些变量从声明开始在整个程序执行期间一直存在。

如果没有显式声明,则所有值被设置为0,只能使用常量表达式初始化静态变量。

a. 外部变量(全局变量):静态存储,作用域为整个文件,外部链接性。在函数外面声明。

//NOTE1:可以使用关键字 extern 重新声明以前定义过的外部变量,称为引用声明,不给变量分配存储空间,只是引用已有变量,但不能初始化。

//NOTE2:只能在引用其他地方(或函数)定义的变量的声明中使用关键字 extern。

//NOTE:3:可以使用C++作用域解析操作符(::)来访问被隐藏的外部变量。

#include <iostream>
using namespace std;

int a = 10;

int main(){
    {
        //extern int a = 5 invalid initialize
        extern int a;
        a = 5;
        cout << a << " " << &a << endl;   //5 0x4b8000
        cout << ::a << " " << &(::a) << endl;  //5 0x4b8000
    }
    return 0;
}

//NOTE4:对于外部链接性变量,有且只有一个文件中包含改变量的定义。其它文件中要是用该变量必须在引用声明送使用关键字 extern。 

//file 1
#include <iostream>
using namespace std;

int a = 10;  //全局变量

void show();
int main(){
    {
        int a = 5;
        cout << a << " " << &a << endl;  //5 0x6dfeec  局部变量
        cout << ::a << " " << &(::a) << endl; //10 0x4b8000  全局变量
        show(); //10 0x4b8000  全局变量

        cout << a << " " << &a << endl; //5 0x6dfeec
        cout << ::a << " " << &(::a) << endl; //1 0x4b8000
        show(); //1 0x4b8000
    }
    return 0;
}

//file 2
#include <iostream>
using namespace std;

void show(){
    extern int a;  //引用声明 file1中的外部变量 a 
    cout << a << " " << &a << endl; 
    a = 1;  // 改变的是 file1中的外部变量 a 的值
}

b. 静态外部变量(静态全局变量):静态存储,作用域为整个文件,内部链接性。在函数外面使用关键字 static 声明。

//NOTE:链接性为内部的变量只能在其所属的文件中使用。

c. 静态局部变量:静态存储,作用域为代码块,无链接性。在代码块内使用关键字 static 声明。

//NOTE1:在代码块不处于活动状态时仍然存在。因此在两次函数调用之间,静态局部变量的值保持不变。

//NOTE2:尽管多次调用函数,但是静态局部变量只会被初始化一次

#include <iostream>
using namespace std;

static int a = 10; //静态全局变量

void show(int& b);
int main(){
    static int b = 1; //静态局部变量
    cout << "b: " << " " << b << " " << &b << endl;
    for(int i = 0; i < 5; i++){
        show(b);
    }
    return 0;
}
void show(int& b){
    static int total = 0; //静态局部变量
    total += b;
    cout << "total: " << " " << total << " " << &total << endl;
}
/*OUTPUT
b:  1 0x4b8004
total:  1 0x4c600c
total:  2 0x4c600c
total:  3 0x4c600c
total:  4 0x4c600c
total:  5 0x4c600c
*/

 5. 动态分配存储空间

使用C++操作符new(或C函数 malloc() )分配内存。使用delete释放内存。因此动态内存的分配和释放顺序取决于new和delete。

//NOTE1:通常编译器有三块独立的内存,一块用于静态变量(可细分),一块用于自动变量,一夸用于动态存储。

//NOTE2:使用new创建的变量必须在函数中,因为函数外的是静态存储变量只能用常量表达式初始化。

6. 布局new操作符 P280

1)布局new操作符可以分配指定位置的内存。常规new在动态管理的堆中获得可用存储空间。

2)布局操作符使用传递给它的地址,无论该地址使用没有,也不查找未使用的内存块。常规new操作符查找新的内存块。

3)布局new操作符不能使用delete释放空间。

#include <iostream>
#include <new>

const int BUF = 512;
const int n = 5;
char buffer[BUF];  //静态内存区

int main(){
    using namespace std;
    double *pd1, *pd2;
    pd1 = new double[N];  //堆(动态内存区)
    pd2 = new (buffer) double[N];  //静态内存区
}
原文地址:https://www.cnblogs.com/tristatl/p/13058216.html