写在前面
好久没有更新文章了,项目开发的进程需要暂停了,因为最近一个月需要备战CCPC的省赛和蓝桥国赛。在近日训练算法的时候,经常发现使用C++写算法的dalao的程序里,会给main
函数前面加上关键字signed
而不是int
,以避免先前对int
关键字宏定义为long long
的冲突(main
函数返回值类型只能是int
)。这似乎本没什么值得注意的,但signed
这个不太常见的关键字激发了我对其他未曾使用过的数据类型关键字的兴趣。更多认识这些,也便于我之后更知其所以然地使用C++设计算法。也顺便触类旁通,复习一下认识过程中遇到的旧知识。
定义或是改变变量类型的关键字,我们更多称其为修饰符,下文便一直使用这个名词。
signed
表示变量可以存储负数。对于整型变量来说,signed 可以省略,因为整型变量默认为有符号类型。
wchar_t
表示宽字符类型,可以存储 Unicode 字符。单个汉字就是一个很典型的宽字符,不信你试试看用一个字符变量存储汉字,是一定会报错的。
不能够用一个字节表示的字符,我们都不能使用char修饰符,这跟编码有关: 1. ASCI码中,一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。 2. UTF-8编码中,一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。 3. 在Unicode编码中,一个英文等于两个字节,一个中文(含繁体)等于两个字节。 4. 在UTF-16编码中,一个英文字母字符或一个汉字字符存储都需要2个字节²。 5. UTF-32编码中,世界上任何字符的存储都需要4个字节。
const
const当然很常用,但是当我们想要自定义排序规则时,你会习惯性加上const
且了解它的作用吗?
cpp
typedef struct value_label{
int value;
int label;
friend bool operator < (const value_label &a,const value_label &b){
return a.value > b.value;
}
}t;
const
这个修饰符的重要性就在于,在定义的函数中,可以保证变量不被修改,起到一定的保护作用,
不光可以用来定义常量。
除了以上的用法,我们也可以对函数使用const
修饰,作用就是表明该函数不会修改类/结构体内的成员变量。
volatile
这就是和const
相对的修饰符了。它允许该变量的值可能会被程序以外的因素改变,如硬件或其他线程。这和Java当中同名的volatile
修饰符很像。
Java当中volatile修饰符的作用:
1.并发环境可见性:volatile修饰后的变量能够保证该变量在线程间的可见性,线程进行数据的读写操作时将绕开工作内存(CPU缓存)而直接跟主内存进行数据交互,即线程进行读操作时直接从主内存中读取,写操作时直接将修改后端变量刷新到主内存中,这样就能保证其他线程访问到的数据是最新数据.
2.并发环境有序性:通过对volatile变量采取内存屏障(Memory barrier)的方式来防止编译重排序和CPU指令重排序,具体方式是通过在操作volatile变量的指令前后加入内存屏障,来实现happens-before关系,保证在多线程环境下的数据交互不会出现紊乱,保护线程的安全。
restrict
由 restrict 修饰的指针是唯一一种访问它所指向的对象的方式。只有 C99 增加了新的类型限定符 restrict。
mutable
表示类中的成员变量可以在 const 成员函数中被修改。但本来由const
修饰的函数就是保证变量不被修改,又设计出来个可以改变变量的mutable
,也许是增加灵活性吧……
static
用于定义静态变量,表示该变量的作用域仅限于当前文件或当前函数内,不会被其他文件或函数访问。而与我们的认识有所不同的是,由static
修饰的变量其值是可以改变的,并不像Java用来定义不可变的常量。
cpp
void example_function() {
static int count = 0; // static 关键字使变量 count 存储在程序生命周期内都存在
count++;
}
register
用于定义寄存器变量,表示该变量被频繁使用,可以存储在CPU的寄存器中,以提高程序的运行效率。但是它只是建议编译器将变量存储在寄存器中,究竟会不会,还得由编译器说了算。
参阅资料
- 菜鸟教程
- 知乎