C++学习(5)内存模型、静态变量等(易错点、重要概念)

关于#include"" 和#include<> 的区别问题

使用<> 给编译器的提示是:
存储标准头文件的主机系统的文件系统中查找头文件
使用 “” 给编译器的提示是:
首先在当前工作目录源代码目录中查找,若没有则再到标准位置文件中查找。

关于防止多次调用同一头文件的问题

C/C++都不允许在同一文件中多次调用同一个头文件,不然会导致编译出错。
为了解决这种问题,一般采用的方法是

#ifndef BUG_H_
#define BUG_H_
 头文件内存
 #endif 

这样操作,就是在编译时,让编译器读到第一次该头文件后,忽略后面再读到的该头文件内容直接跳到#endif,由此防止编译的出错

静态持续变量、自动变量

C++为存储静态持续性变量提供了3中链接性:
外部链接性(可在其他文件中进行访问)
内部链接性(只能在当前文件中访问)
没有链接性(只能在当前函数或者代码块中访问)
在存储管理上,编译器将分配固定的内存给来存储所有静态变量

此外自动变量,就下面代码中的 llam ,这个在函数中声明的函数参数或变量的存储持续性是自动的,作用域为局部,没有链接性,函数结束后,这种变量分配的存储空间随之释放。
(自动变量随之函数的开始和结束而增减,所以使用“栈”来对这部分变量内存进行管理)


int global = 10;//外部链接性,静态持续变量

static int  global_1 = 20;//内部链接性,静态持续变量

void test()
{
	static int global = 20;//没有链接性,静态持续变量
	int llam =10;//自动变量
}
int main()
{
    return 0;
}

寄存器变量,即在变量定义前加关键字:register ,用的少,用到的时候在做笔记

静态持续性 与 外、内、无链接性

(1)与外部链接性
首先,链接性为外部的变量统称外部变量,也叫全局变量。
1、单定义规则
C/C++规定了外部变量必须声明它,且只能有一次定义,故C++提供了两种变量声明:
1)定义,如double up;,这种是会给变量分配存储空间的,默认设置为0;
2)引用声明,这种不会给变量分配存储空间,它是引用已有的变量。
引用声明的关键词:extern ,且声明不能进行初始化,否则声明为定义,导致分配存储空间:
说明一下引用声明的例子:(就是变量跨文件调用
第一个文件 file1.cpp

//file1.cpp
#include <iostream>
using namespace std;

int file01 = 10;//定义了一个外部变量

int main()
{
}

第二文件 file2.cpp

//file2.cpp
#include <iostream>
using namespace std;
//引用file1.cpp中的file01变量,不分配存储空间,直接引用第一个文件定义好的
extern int file01;//所以不能初始化

int main()
{
}

extern 指示使用了第一个文件定义的变量file01

:局部定义的变量 会隐藏 全局定义的变量

2、作用域解析运算符(::)
该运算符是表示使用变量的全局版本,例:(接上面的file2.cpp)——::file01

#include <iostream>
using namespace std;
//引用file1.cpp中的file01变量,不分配存储空间,直接引用第一个文件定义好的
extern int file01;//所以不能初始化

void updata()
{
    file01 = file01-1;//修改了外部变量file01,值随之改变
}
void local()
{
    int file01 =10;
    cout << file01 <<endl;//输出为10,局部屏蔽全局
    cout <<::file01 <<endl;//输出外部变量file01的值
}
int main()
{
  updata();
  local();//
}

(2)与内部链接性
即采用 static 关键字,在函数外,即链接性为内部的变量只能在其所属的文件中被使用
注意的点:

1)若在一个工程两个CPP文件分别使用常规方法定义同名的外部变量
这样做会使编译出错;

错误示范:

//file1.cpp
int exx = 20;
...
-------------------
//file2.cpp
int exx = 10;

2)为了避免 1)同名外部变量的问题,可以采用 static 关键字的方法,static 将该变量变成一个内部链接性的静态变量,就可以隐藏常规的外部变量

正确示范:

//file1.cpp
int exx = 20;
...
-------------------
//file2.cpp
static int exx = 10;

(3)与无链接性(局部变量)
任然采用 static 关键字,但是在代码块中(函数中),作用域被限定在代码块内;

需要注意的点

1、在一个函数中使用 static 定义一个局部变量后,在两次调用函数间隔期间,该变量的值不会发生改变,将继续延续上一次调用函数的最后状态值

2、对1)的进一步说明是 静态局部变量 只在程序启动时初始化一次,此后程序运行中第二次调用函数时,将不会像自动变量那样再次初始化了。

例:

#include <iostream>
using namespace std;

int global = 10;//外部链接性,静态持续变量

static int  global_1 = 20;//内部链接性,静态持续变量

void test()
{
	static int global = 20;//没有链接性,静态持续变量
	global = global - 1;
	cout << global << endl;
}

int main()
{
	for (int i = 0; i <= 2; i++)
	{
		test();
	}
}

输出:
19
18
17
显然 test()函数中的 global 每次调用时的值都不一样。

静态持续性与三性的总结:

(1)可以使用外部变量在多文件程序的不同部分之间共享数据;
(2)可以使用链接性为内部的静态变量在同一个文件中的多个函数之间共享数据;
(3)如果作用域为整个文件的变量为静态的,就不必担心其名称与其他文件中的作用域为整个文件的变量发生冲突

说明符与限定符

存储说明符作用
auto用于自动类型推断
register声明指示寄存器变量存储
static作用域声明为整个文件时,表示内部链接;作用域为函数代码块时,表示无链接性
extern引用声明,引用其他文件的外部变量
thread_local指出变量的持续性与所属的线程持续性相同,两者关系与静态变量之于整个程序相同
mutable即使结构(或者类)变量为const,其中的某个成员也可以被改变(在成员变量中加上该关键词)
限定符说明
const内存初始化后,程序将不能再对其变量进行修改
volatile即使程序代码没有对内存单元进行修改,其值也可能发生变化 (我暂时也不太懂得。。。)

const 的深入说明:
(1)默认情况下全局变量的链接性是外部的,但是当在前面加上 const 后,其链接性将变为内部,也就是说,const 对于全局变量就相当于static对于全局一样;
(2)

函数与链接性

(1)默认情况下,函数的链接性是外部的,即可以在文件之间共享的;
(2)可使用关键字static 将函数链接性设置为内部,这样该函数就只能用于该文件了,或者说该函数只在该文件可见。
(3)第二点的特点还可以使得其他文件中可以定义同名函数(这个对于Unity中的C#似乎很有帮助)

名称空间(重要)

首先,名称空间的作用在于:以便更好地控制名称的作用域
特性:一个名称空间不会与另外一个名称空间的相同名称发送冲突,且允许程序的其他部分使用该名称空间中声明的东西。
名称空间创建的关键字:namespace

namespace Jack{
	double pail;
	void fetch();
	struct Well{...};
	....
}

说明:
(1)名称空间可以是全局的,也可以位于另外一个名称空间中,但是不能在代码块或函数中;
(2)默认情况下,名称空间中声明的名称的链接性是外部的;
(3)全局名称空间,其对应于文件级声明区域,与全局变量的性质差不多;
(4)任何名称空间中的名称都不会与其他名称空间中的名称发生冲突;
(5)访问名称空间中的名称的方法:通过使用作用域解析运算符::),例如:

//接上面的
Jack::pail = 10.0;//初始化jack名称空间中的变量
Jack::fetch();//调用jack名称空间中的函数
Jack::Well hill;//创建jack名称空间中的结构体类型变量

using声明和using编译指令

#include <iostream>
#include<string>
using namespace std;//使用using编译指令使得所有名称都可用

namespace Jack {
	double pail;
	void fetch();
	struct well
	{
		string name;
		int age;
	};
}

using Jack::pail;//使用using声明,使得Jack中的pail为全局名称空间

using namespace Jack;//使用using编译指令使得Jack中的所有名称都可用

int main()
{
    
}

void Jack::fetch()//在对jack名称空间中的fetch()函数进行定义
{

}

注意:以下这样做是错的,编译器是不允许同时使用两个using声明的,这样会导致二义性。

//错误定义
using Jack::pail;
using Jill::pail;
pail =10 ;

另外,一般说我们更喜欢这么写,使得std名称空间的所有名称都导入到全局名称空间中,这样方便;另一方面,如果系统不知处名称空间时,也可以将这两行替换成:#include<iostream.h>

#include <iostream>
using namespace std;//使用using编译指令使得所有名称都可用

-------
//替换以上两行
#include<iostream.h>

---------
//名称空间的支持者更喜欢的做法是
#inlcude<iostream>
std::cin>>x;
std::cout<<x;
//或
using std::cin;
cin >> x;

名称空间的嵌套

namespace Jill {
	namespace elements {
		int xo;
	}
}//默认全局
//调用
int main()
{
	Jill::elements::xo = 10;
}

技巧:
一般来说,一个工程中第一个是头文件,头文件一般包含:常量、结构定义、函数原型,一些常用的名称空间可以定义在头文件中,待cpp调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LionelMartin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值