static
1)用static修饰局部变量:使其变为静态存储方式(静态数据区),那么这个局部变量在函数执行完成之后不会被释放,而是继续保留在内存中。
2)用static修饰全局变量:使其只在本文件内部有效,而其他文件不可连接或引用该变量。
3)用static修饰函数:对函数的连接方式产生影响,使得函数只在本文件内部有效,对其他文件是不可见的(这一点在大工程中很重要很重要,避免很多麻烦,很常见)。这样的函数又叫作静态函数。使用静态函数的好处是,不用担心与其他文件的同名函数产生干扰,另外也是对函数本身的一种保护机制。
const
const主要用来修饰变量、指针、引用、函数形参和类成员函数:
1)用const修饰常量和变量:
const int MAX_VALUE = 100;
const float PI = 3.14159;
const int num = 10;
定义时就初始化,以后不能更改。
2)用const修饰指针:
const int* ptr = #
ptr
是一个指向 int
类型常量的指针,即指针所指向的值不能通过 ptr
修改。
3)用const修饰引用:
const int& ref = num;
ref
是一个指向 int
类型常量的引用,即引用所绑定的值不能通过 ref
修改 。
4)用const修饰形参:
func(const int a){};
该形参在函数里不能改变
5)用const修饰类成员函数:
void printValue() const;
在上述示例中,const
修饰的成员函数 printValue()
是一个常量成员函数,它承诺不会修改类的任何非静态成员变量
const的使用有助于提高代码的可读性、可维护性和安全性。它可以防止对常量的意外修改,同时也提供了一些编译时的优化机会。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
例子:
const 限定一个数据为只读属性。
1.const char p; 限定变量 p 为只读。
2.const char *p; p 为一个指向 char 类型的指针,const 限定 p 指向的数据为只读。所以 *p 的值不能被修改,而指针变量 p 本身的值可以被修改。
3.char * const p; 限定此指针变量为只读,所以 p 的值不能被修改,而 *p 的值可以被修改。
4.const char *const p; 两者皆限定为只读,不能修改。
1.const int a;
2.int const a;
3.const int *a;
4.int * const a;
5.int const * a const;前两个的作用是一样,a是一个常整型数。
第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。
第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。
最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。
volatile
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。
精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量在内存中的值,而不是使用保存在寄存器里的备份(虽然读写寄存器比读写内存快)。
它主要用于处理与多线程、中断处理和硬件寄存器等相关的情况。
防止编译器优化:编译器在优化代码时会尝试将变量的访问操作优化为更高效的方式,例如将变量的值缓存在寄存器中。然而,对于某些特殊的变量,如多线程环境下的共享变量、中断处理中的标志位、硬件寄存器等,这种优化可能会导致意外的行为。使用
volatile
关键字可以告诉编译器不要对该变量进行优化,确保每次访问都从内存中读取或写入。处理多线程共享变量:在多线程编程中,当一个变量被多个线程共享并且可能被一个线程修改时,需要使用
volatile
关键字来确保线程之间的可见性。这样可以防止编译器对共享变量的优化,确保每个线程都能正确地读取到最新的值。处理中断和硬件寄存器:在中断处理程序中,某些变量可能由硬件直接修改,而不是通过常规的变量赋值操作。在这种情况下,使用
volatile
关键字可以确保编译器不会对这些变量的访问进行优化,以避免出现不一致的行为。