2.1 基本内置类型
- c++规定
sizeof(long long) >= sizeof(long) >= sizeof(int) >= sizeof(short)
- c++11新定义类型
long long
- 类型
char
具体是unsigned char
还是signed char
跟编译器的实现有关系
- 如果你的数值超过了int,建议选用
long long
- 算术表达式中不要使用
char
或bool
,如果必须使用,一定要明确指明signed
还是unsigned
- 执行浮点运算直接用
double
,float
精度太低,运算效率甚至反而比double
低
四大数据模型。
区别主要是int、long、指针类型。long long所有模型都是64位。
- LP32 windows16位系统( int 为 16 位, long 和指针为 32 位)
- ILP32 win和linux的32位系统( int 、 long 和指针为 32 位)
- LLP64 windows64位系统( int 和 long 为 32 位,指针为 64 位)
- LP64 unix64位系统( int 为 32 位, long 和指针为 64 位)
整数类型可以理解为只有int,由两个维度的修饰符来修饰。由长度修饰符时int可省略
- 符号修饰符:signed unsigned
- 长度修饰符:short、 long、 long long
转换规则如下
- 浮点类型转整数时丢掉了小数点部分,不是四舍五入。
- c++/java/c的%是取余,python的//和%是取模。取模结果的符号跟除数一致,取余跟除数一致。
- 负数转有符号数时,只是解析规则发生变化。也可以理解为负数加上无符号数的模(即无符号数的计量范围,如char就是256),所以-1转
char
相当于-1+256=255
- 无符号溢出时,结果是该值对该类型表示数值总数(除数)取模后的余数。这个规则对负数也是一样的。比如-1赋值给
char
,相当于-1 mod 256,
- 带符号类型溢出结果是未定义的。
- 当一个算数表达式中既有无符号数又有带符号数时,则都会转成无符号数。
字面值
- 0x开头代表十六进制,0开头代表八进制,0b代表二进制(c++14)
- 十进制字面值带符号,以int、long、long long中尺寸最小的那个。
- 八进制、十六进制、二进制可能带也可能不带,是int、unsigned int、long、unsigned long、long long、unsigned long long中的最小者。
- 字符串字面值可以有
\x4d
或\40
这种十六进制或八进制的转义序列。八进制时只有斜杠后边三个数字是转义序列的。十六进制则使用\x
后边所有的数字。
- 字符串字面值有L表示wchar_t,u代表char16_t,U代表char32_t,u8代表UTF-8的char。
- 数字字面值可选U L LL的组合来控制符号和最小类型。
2.2 变量
初始化注意事项
- 初始化和赋值时不同的操作,虽然他们都使用了等号。
- 列表初始化既可以用来赋值,也可以用来初始化。
- 列表初始化如果会导致信息丢失时,会发生编译错误。
- 内置类型变量的默认初始化由位置决定,定义于任何函数体外的变量或static变量都会被初始化为0,否则时未定义。建议初始化每一个内置类型的变量。
- 类类型的对象初始化由类本身决定。
声明和定义
- 如果只想声明一个变量而不定义它,在变量名前添加关键字extern切不要初始化它。初始化会抵消extern。
- 定义只能有一次,声明可以有多次。
标识由字母、数字、下划线组成,且必须以字母、下划线开头,大小写敏感
作用域名
- 在所有花括号之外定义的变量有全局作用域名,整个程序都能使用。
- 内存作用域可以覆盖外部使用。
- ::可以访问全局作用域名
2.3 复合类型
引用和指针
- 引用必须初始化,无法让引用重新绑定到其他对象。
- 引用本身不是对象,不能定义引用的引用
- 定义指针和引用时&或*属于标识符,一行语句定义多个变量时各自添加。
- 指针本身时对象,不需要定义时赋值,可以存在对指针的引用
- 空指针使用nullptr初始化。
- 理解符合类型的定义,可以从右向左阅读,离变量名越近影响越大。括号会有更高的优先级。
2.4 const限定符
- const对象必须初始化,且不能再被修改。它可以用来取初始化其他对象。
- const对象仅在当前文件内有效。多个文件中的同学const变量时独立的。
- 多文件共享const变量的方法是声明和定义时都加extern关键字。
- 对const对象的引用不能被用作修改它绑定的对象。
- 初始化常量引用可以用任意能转换到该引用类型的表达式,比如非常量对象,字面值,表达式,临时对象等。
const和指针
- 要存放常量对象的地址,只能使用指向常量的指针。常量指针是指指针本身是常量。
1
2
|
const int *p1 = nullptr; //指向常量的指针
int * const p2 = nullptr; //常量指针
|
- 允许指向常量的指针指向非常量对象。
顶层const和底层const
- 顶层一般指
const
修饰的变量本身不可被修改,底层指无法通过该变量间接修改指向的对象。
- 普通对象一般都是顶层
const
,如int,类对象等。
const
修饰引用时,只能是底层const
。因为引用本身不可变,所以它本身已经是顶层const
了。
- 指针既可以是底层
const
,又可以是顶层const
。
- 顶层
const
无法区分重载函数。
- 拷贝时顶层
const
没有影响,但底层const
必须相同或可以转换才可以拷贝。一般非const
可以转到const
。
常量表达式constexpr
- 值不会改变且编译过程中就能得到计算结果的表达式。如字面量,用常量表达式初始化的const对象,自定义类型不能被定义成constexpr
- 声明为constexpr的变量一定是常量,且定义的同时必须用常量表达式初始化。
- 指针和引用都能定义成constexpr,但constexpr指针的初始值只能为nullptr或0,或者存储于某个固定地址中的对象(函数体外的,如全局变量、静态变量、函数体内的静态变量等)。
- 如果你认为变量时一个常量表达式,就把它声明成constexpr类型
- 允许函数也定义为constexpr类型
- constexpr声明中如果定义了指针,constexpr仅对指针有效,与指针无关,也就是一个顶层的效果。如
1
2
3
4
|
const int *p = nullptr; //p是一个指向整形常量的指针
constexpr int *q = nullptr; //q是一个指向整数的常量指针
constexpr const int *o = nullptr; //o是一个指向常量的常量指针。
const int * const r; //r也是是一个指向常量的常量指针,但它不是常量表达式,初始化没要求。
|
2.5 处理类型
类型别名
- 定义类型别名的两种方法: typedef using关键字
1
2
3
4
|
//以下两个表达式效果一致。
typedef double mydouble;
using mydouble2 = double;
>```
|
- 直接尝试替换类型别名的方法取理解语句是错误的
1
2
3
|
typedef char *pstring;
const pstring cstr; //常量指针,const修饰的是cstr
const pstring *ps; //ps是一个指针,指向一个指向char的常量指针
|
auto
- auto让编译器通过初始值来推算变量的类型,auto类型的变量必须有初始值。
- 一条语句用auto声明多个变量时基础类型必须一样。
- auto类型会同时忽略引用和顶层const,希望auto类型是const或引用要明确指出
- 如果设置auto为引用,则初始值的顶层const也会一起保留。
1
2
3
|
const int i = 0;
auto &j = i; //j的类型为const int &
j = 100; //error
|
- auto类型的推导跟模板参数类型的推导基本类似
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
int a = 10;
const int ca = 10;
int &ra = a;
const int &cra = a;
//auto非指针和引用:忽略右边的引用和顶层const
auto t1 = a; //int
auto t2 = ca; //int
auto t3 = ra; //int
auto t4 = cra; //int
//auto是指针或引用:如果右边是引用,忽略掉它的引用,然后去匹配,保留顶层const
auto & t11 = a; //int &
auto & t12 = ca;//const int &
auto & t13 = ra;//int &
auto & t14 = cra;//const int &
|
decltype
使用场景:希望推导出表达式的类型,但不想用表达式的值初始化变量.
- 如果decltype的表达式是一个变量,则变量的顶层const和引用都在。
- 解引用操作符得到的是引用
- decltype如果是双层括号,则得到引用类型
1
2
3
|
int i = 0;
decltype((i)) d; //错误:d是未初始化的int &
decltype(i) e; //正确: e是int
|