参考自:https://blog.csdn.net/qq_38677814/article/details/79368632,仅作学习记录。
在我们的内存中,会分为三块:静态区,堆区,栈区。
- 外部变量和全局变量存放在静态区,
- 局部变量存放在栈区,
- 动态开辟的内存存在堆区。
auto
auto类型:其实在函数中的局部变量,不加特殊声明,都是auto变量,但是关键字”auto”可以被省略。这些变量在函数被调用时分配存储方式,函数调用结束后这些存储空间就被释放了。
C语言中隐含的存储类型是 auto
static
总结:限制函数或变量的作用域,别的函数或cpp调用不了,且变量调用结束不消失。
static类型: 静态类型数据,数据存放在全局数据区,但作用域只是本文件/函数 中,所以你可以在两个不同的文件/函数内部申明同名的static变量,但是它们是两个不同的全局变量。
两个注意点:
- ①如果是定义在函数内,那么函数外不能对其访问。
- ②如果是定义在函数外,那么该对象具有内部链接,其它程序文件不能对其访问
函数调用结束后,这些变量不消失,而保留当前数据,下一次调用时变量的值为上一次调用完成后的值。
extern
总结:放大函数或变量的作用域,别的cpp也能用。
函数在.h头文件里的声明默认是extern类型的,不用显示去写
详见此篇博客
外部变量声明,是指这是一个已在别的地方定义过的对象,这里只是对变量的一次重复引用,不会产生新的变量。
这在复杂的大型工程中会用到,比如我在我的程序中需要用到小明写的程序中的变量a,那么我在自己的程序中声明 extern int a; 告诉编译器这是别人模块中的变量,我拿过来用一下。
extern的原理很简单,就是告诉编译器:“你现在编译的文件中,有一个标识符虽然没有在本文件中定义,但是它是在别的文件中定义的全局变量,你要放行!”
register
Register修饰符暗示编译程序相应的变量将将被频繁使用,如果可能的话,应将其保存在CPU的寄存器中,以指加快其存取速度。但是,使用register修饰符有几点限制:
- (1)只有局部自动变量和形式参数可以作为寄存器变量,其他(如全局变量)不行。
- (2)CPU的寄存器数目有限,因此,即使定义了寄存器变量,编译器可能并不真正为其分配寄存器,而是将其当做普通的auto变量来对待,为其分配栈内存。当然,有些优秀的编译器,能自动识别使用频繁的变量,如循环控制变量等,在有可用的寄存器时,即使没有使用 register 关键字,也自动为其分配寄存器,无须由程序员来指定。
- (3)局部静态变量不能定义为寄存器变量。因为一个变量只能声明为一种存储类别。
其实这个变量已经过时,因为现在的计算机处理速度够快,所以很少使用
volatile
参考博客
volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。
volatile的本意是“易变的”,由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。比如:
程序的本意是希望ISR_2中断产生时,在main当中调用do_something函数,但是,由于编译器判断在main函数里面没有修改过i,因此可能只执行一次对从i到某寄存器的读操作,然后每次if判断都只使用这个寄存器里面的“i副本”,导致do_something永远也不会被调用。
如果变量加上volatile修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。此例中i也应该如此说明。
一般说来,volatile用在如下的几个地方:
- 1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
- 2、多任务环境下各任务间共享的标志应该加volatile;
- 3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
- 另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。
explicit
C++提供了关键字explicit,声明为explicit的构造函数不能在隐式转换中使用。
1)C++的类型转换分为两种,一种为隐式转换,另一种为显式转换。
2)C++中应该尽量不要使用转换,尽量使用显式转换来代替隐式转换。
- 隐式转换是系统跟据程序的需要而自动转换的。
//1)算术表达式
int m = 10;
double n = m;//n = 10.0;隐式把m转为double类型
int m = 10;
float f = 10.0;
double d = m + f;//n = 20.0;隐式把m和f转为double类型
//2)赋值
int *p = NULL; //NULL(0)隐式转换为int*类型的空指针值
//3)函数入参
float add(float f);
add(2); //2隐式转换为float类型
//4)函数返回值
double minus(int a, int b)
{
return a - b; //返回值隐式转换为double类型
}
//————————————————————————————————————————————————————————————————
void fun(CTest test);
class CTest
{
public:
CTest(int m = 0);
}
fun(20);//隐式转换
- 显式转换也叫强制转换,是自己主动让这个类型转换成别的类型。
int m = 5;
char c = (char)m;//显式把m转为char类型
double d = 2.0;
int i = 1;
i += static_cast<int>(d);//显式把d转换为int类型
//————————————————————————————————————————————————————————————————
void fun(CTest test);
class CTest
{
public:
explicit CTest(int m = 0);
}
fun(20);//error 隐式转换
fun(static_cast<CTest>(20)); //ok 显式转换