辜老师的C++课堂笔记

不代表全部内容

第二章 类型、常量及变量

2.1 C++的单词

单词包括常量、变量名、函数名、参数名、类型名、运算符、关键字等。
关键字也被称为保留字,不能用作变量名。
预定义类型如int等也被当作保留字

char16_tchar32_t是C++11引入的两种新的字符类型,用于表示特定大小的Unicode字符
例如 char16_t x = u'马';
wchar_t表示char16_t ,或char32_t
nullptr表示空指针

需要特别注意的是:char可以显示地声明为带符号的和无符号的。因此C++11标准规定char,signed char和unsigned char是三种不同的类型。
但每个具体的编译器实现中,char会表现为signed char和unsigned char中的一种。

unsigned char ua = ~0;
printf("%d  ", ua);//输出255
signed char ub = ~0;
printf("%d  ", ub);//输出-1
char uc = ~0;
printf("%d", uc);//输出-1

2.2 预定义类型(内置数据类型)及值域和常量

2.2.1 常见预定义类型

类型的字节数与硬件、操作系统、编译有关。假定VS2019采用X86编译模式。
void:字节数不定,常表示函数无参或无返回值。

void
是一个可以指向任意类型的指针类型。它本质上是一个
“无类型”*的指针,这意味着它可以指向任何类型的数据,而不关心具体的数据类型。

	int n = 0721;//前置0代表8进制
	double pi = 3.14;
	void* p = &n;
	cout << *(int*)p << endl;//不能直接解引用哦
	p = &pi;	
	cout << *(double*)p << endl;
  • bool:单字节布尔类型,取值false和true。
  • char:单字节有符号字符类型,取值-128~127。
  • short:两字节有符号整数类型,取值-32768~32767。
  • int:四字节有符号整数类型,取值-231~231-1 。
  • long:四字节有符号整数类型,取值-231~231-1 。
  • float:四字节有符号单精度浮点数类型,取值-1038~1038。
  • double:八字节有符号双精度浮点数类型,取值-10308~10308。
    注意:默认一般整数常量当作为int类型,浮点常量当作double类型。
  • char、short、int、long前可加unsigned表示无符号数。
  • long int等价于long;long long占用八字节。
  • 自动类型转换路径(数值表示范围从小到大):
    char→unsigned char→ short→unsigned short→ int→unsigned int→long→unsigned long→float→double→long double。
    数值零自动转换为布尔值false,数值非零转换为布尔值true。
  • 强制类型转换的格式为:
    (类型表达式) 数值表达式
  • 字符常量:‘A’,‘a’,‘9’,‘\’’(单引号),‘\’(斜线),‘\n’(换新行),‘\t’(制表符),‘\b’(退格)
  • 整型常量:9,04,0xA(int); 9U,04U,0xAU(unsigned int); 9L,04L,0xAL(long); 9UL, 04UL,0xAUL(unsigned long), 9LL,04LL,0xALL(long long);
    这里整型常量的类型相信大家看后面的字母也能看出来,例如L代表long,U代表unsigned

2.2.2预定义类型的数值输出格式化

  • double常量:0.9, 3., .3, 2E10, 2.E10, .2E10, -2.5E-10
  • char: %c; short, int: %d; long:%ld; 其中%开始的输出格式符称为占位符
  • 输出无符号数用u代替d(十进制),八进制数用o代替d,十六进制用x代替d
  • 整数表示宽度如printf(“%5c”, ‘A’)打印字符占5格(右对齐)。%-5d表示左对齐。
  • float:%f; double:%lf。float, double:%e科学计数。%g自动选宽度小的e或f。
  • 可对%f或%lf设定宽度和精度及对齐方式。“%-8.2f”表示左对齐、总宽度8(包括符号位和小数部分),其中精度为2位小数。
  • 字符串输出:%s。可设定宽度和对齐:printf(“%5s”,”abc”)。
  • 字符串常量的类型:指向只读字符的指针即const char *, 上述”abc“的类型。
  • 注意strlen(“abc”)=3,但要4个字节存储,最后存储字符‘\0’,表示串结束。

2.3 变量及其类型解析

2.3.1 变量的声明和定义(C++11标准3.1节)

  • 变量说明:描述变量的类型及名称,但没有初始化。可以说明多次
  • 变量定义:描述变量的类型及名称,同时进行初始化。只能定义一次
  • 说明例子:extern int x; extern int x; //变量可以说明多次
  • 定义例子:int x=3; extern int y=4; int z; //全局变量z的初始值为0
  • 模块静态变量:使用static在函数外部定义的变量,只在当前文件(模块)可用。可通过单目::访问。
  • 局部静态变量:使用static在函数内部定义的变量。
static int x, y; //模块静态变量x、y定义,默认初始值均为0
int main( ){    
    static int y;       //局部静态变量y定义, 初始值y=0
    return  ::y+x+y;//分别访问模块静态变量y,模块静态变量x,局部静态变量
} 

为了允许把程序拆分成多个逻辑部分来编写,C++支持分离式编译(separation compilation),即将程序分成多个文件,每个文件独立编译。
为了支持分离式编译,必须将声明(Declaration)定义(Definition)区分开来。声明是使得名字(Identifier,如变量名)为其它程序所知。而定义则负责创建与名字(Identifier)相关联的实体,如为一个变量分配内存单元。因此只有定义才会申请存储空间。
One definition rule(ODR):只能定义一次,但可以多次声明
如果想要声明一个变量而非定义它,就在前面加关键字extern,而且不要显示地初始化变量:

extern int i;   	//变量的声明
int i;//变量的定义(虽没有显示初始化,但会有初始值并分配内存单元存储,即使初始值随机)

任何包含显式初始化的声明成为定义。如果对extern的变量显式初始化,则extern的作用被抵消。
extern int i = 0; //变量的定义
声明和定义的区别非常重要,如果要在多个文件中使用同一个变量,就必须将声明和定义分离,变量的定义必须且只能出现在一个文件中,而其他用到该变量的文件必须对其声明,而不能定义。
例如,头文件里不要放定义,因为头文件可能会被到处include,导致定义多次出现。

值得一提的是C++17引入了 inline 变量,这允许在多个翻译单元中定义同一个全局变量而不引发重复定义的链接错误。inline 变量使得变量像 inline 函数一样,在多个文件中共享同一个定义。
而在之前的标准中,inline只能用于函数而不能用于变量

// header.h
inline int globalVar = 42;

关于其作用,可见C++17之 Inline变量

此外, C++20 引入了模块(Modules)机制,用于替代头文件的传统做法。模块减少了编译依赖并提高了编译速度。在模块中,变量声明和定义的规则更为清晰,模块能够很好地管理变量的可见性和作用范围。
如有兴趣,可见C++20 新特性: modules 及实现现状

2.3.2 变量的初始化(C++11标准8.5节)

变量在创建时获得一个值,我们说这个变量被初始化了(initialized)。最常见的形式为:类型 变量名=表达式;//表达式的求值结果为变量的初始值
用=来初始化的形式让人误以为初始化是赋值的一种。
其实完全不同:初始化的含义是创建变量时设定一个初始值;而赋值的含义是将变量的当前值擦除,而以一个新值来替代。
实际上,C++定义了多种初始化的形式:

int a = 0;
int b = { 0 };
int c(0);
int d{ 0 };

其中用{ }来初始化作为C++11的新标准一部分得到了全面应用(而以前只在一些场合使用,例如初始化结构变量)。这种初始化形式称为列表初始化(list initialization)