初始化/赋值
- 字面值:真实的数,1,5,10等
- 初始化比赋值多的操作:
- 开辟内存空间
- int x=10 对应 mov DWORD PTR [rbp-4] , 10
- 把标识符与内存空间对应起来
- x = y 对应
- mov eax, DWORD PTR //[rbp-8] 这里[rbp-8]和y对应,读出y放到寄存器中
- mov DWORD PTR [rbp-4], eax
- eax 寄存器
- x = y 对应
- 开辟内存空间
- 值和对象都有类型
- 字面值也有类型
- 初始化/赋值可能涉及到类型转换
- int x=10.5 //10.5是浮点数,在保存的时候只保存10
- mov DWORD PTR [rbp-4],10
- int x=10.5 //10.5是浮点数,在保存的时候只保存10
类型详述
类型是编译器的概念,可执行程序中不存在类型概念
- 上图,汇编中没有int等类型
- C++强类型语言,在编译的时候时刻和类型打交道,编译后就没有类型了
- 类型:表示数值的含义及如何解析,更好的描述程序,防止误用
- 内存大小(sizeof),
- 不同编译环境大小可能不一致,
- 64位机器,处理64位更容易,那么int对应的位数不一样
- 取值空间(std::numrilc_limits获取取值空间,头文件limits),超过取值空间会溢出
- int, 4byte,32bit,取值个数
- 超过取值空间会溢出,上溢出到最小值,下溢出到最大值
- 内存大小(sizeof),
- 对齐信息
- int x= 0, 开辟8000-8003字节保存x,而不是7999-8002
- CPU从内存中读写过程中先经过cash。读写单位为cash line,cat coherency_line_size可以获取到cash line 大小
- 如果x的对齐不好,存储在7999-8002,那么cpu要读取(8000-64)~ 7999,8000-8064两次读取,再拼接
- alignof(int) 获取到int类型的对齐信息
- 对齐信息对结构体大小产生影响
- 描述可以执行的操作,加减乘除或者自定义的操作等
- 类型可以划分为基本类型和复杂类型
- 基本(内建)类型
- 字符类型:char,wchar_t,char16_t,char32_t
- char 一般用于表示ASCII编码,刚好256个字符/UTF8编码
- wchar_t 宽字节类型
- 用char32_t表示最全的字符集UNIcode
- 整数类型:
- 带符号整数:int,short ,long,long long,不同类型尺寸不一样,分别4,2,8,8,不同环境不一样,有些环境long long,与long尺寸不一样
- 无符号整数:unsigned + 带符号整数类型
- 浮点类型:float,double,long double
- 可以表示小数
- void
- 字符类型:char,wchar_t,char16_t,char32_t
- 复杂类型:由基本类型组合,变种所产生的类型,可能是标准库引入,或自定义类型
字面值
- 在程序中直接表示为一个具体数值或字符串的值
- 每个字面值都有其类型
- 整数字面值:20(十进制),024(八进制),0x14(十六进制)——int型
- 浮点数:1.3,1e8 ——double型
- 字符字面值:’c’,’\n’,’\x4d’ ——char型
- 字符串字面值:”Hello” ——char[6]型,双引号,后面有’\0’,结束符
- 布尔字面值:true,false ——bool型
- 指针字面值:nullptr ——nullptr_t 型
- 可以在字面值加前缀或者后缀改变类型
- 1.3(double)—— 1.3f (float型)
- 2(int型)—— 2ULL(unsigned long long 型)
- 可以引入自定义后缀改变字面值类型,输入参数类型仅限如下图。应用:定义时间,kg,g等单位
变量
- 对应了一段存储空间,可以改变其中内容
- 变量的类型在其首次声明(定义)时指定
- int x:定义一个变量x,其类型为int
- 变量声明与定义的区别:extern前缀,无前缀,全局变量定义,有前缀为声明
- 变量的初始化与赋值
(隐式)类型转换
- 为变量赋值时可能涉及到的转换:
- bool与整数之间的转换:
- 浮点数和整数之间的类型转换:
- 隐式类型转换不只发生在赋值时
- if判断:if(3),3转为bool值
- 数值比较:(x<y),转为bool值,
- 无符号数和带符号数做比较时,把带符号数转为无符号数,如下,输出0
- std::cmp_XXX(c++20)可以避免上述情况
- 提升转换:小内存类型转为大内存类型,无结果差异
- 压缩转换:精度损失
- unsigned int -> int 会发生数值变化,
复合类性:从指针到引用
指针:一种间接类型
- 特点
- 指向不同的对象
- int x,y;
- int* p = &x;
- p = &y;
- 具有相同的尺寸
- 所有指针都是8个字节,不同类型的指针尺寸仍相同
- 指针保存地址,64位机,内存最大为2^64,所以保存地址需要64bit,即8字节
- 指向不同的对象
- 相关操作
- &:取地址操作符,得到内存空间地址对应的值,
- 通常将地址赋值给指针
- 注意,需要有地址,变量有地址,字面值(右值)无地址
- *:解引用操作符,
- 访问指针保存的首地址,到对应首地址,读取数据
- 指针类型决定读取连续多长内存中的数据
- &:取地址操作符,得到内存空间地址对应的值,
- 指针缺省初始化
- 在函数内局部的,是随机的
- 在全局,值为0,地址0不能解引用,崩溃
- 缺省初始化指向的内存不一定存在
- int *p = NULL/0, 更安全,能报出错误
- 拷贝初始化,存在类型转换,危险。函数重载,
- void fun(int ) void fun(int), fun(0) fun(p),两者调用不同fun,对于int *p = 0,导致行为不同
- nullptr不能隐式转换为0,fun(nullptr)调用fun(int *),不会导致行为不同,程序更稳定
- 拷贝初始化,存在类型转换,危险。函数重载,
- 注意:指针初始化尽量为 int* p = nullptr;
- 指针的定义
- int* p = &val;
- int* p = nullptr;
- 关于nullptr
- 一个特殊的对象,类型(nullptr_t),表示空指针
- 类似于C中的NULL,但更加安全
- 指针与bool的隐式转换:
- 非空指针可以转换为true;
- 空指针转为false
- 指针的主要操作:
- 解引用: *p
- 增加: p = p+1, 指向的位置移动到地址下一个,实际地址移动一个int(类型)长度,4
- 减少:p=p-1,指向的位置移动到地址上一个,实际地址移动一个int(类型)长度,4
- 判等:判断两个指针是否相等
- 比较大小,只在数组中用。在栈里分配,内存按先后顺序,在堆里分配,内存无先后顺序
- void *指针
- 没有记录对象的尺寸信息,可以保存任意地址
- 支持判等操作,不支持加减
- 可以转为任意类型指针,也可以由任意类型指针转为void*,但是丢掉了对象的尺寸信息(类型)
- 指针的指针
- int** pp = &p;
- 指针VS对象,为间接引用。
- 对于自定义的较大的对象,复制操作比较慢,指针减小传输
- 对于不支持复制的对象(独占内存的对象),使用指针
- 指针读写成本高,两次地址访问
- 作为函数参数传入,可以修改指针所指地址内的值
- 指针的问题
常量类型和常量表达式
- 常量表达式:const,只能读不能写
- 编译期
- 防止非法操作:写操作
- 优化程序逻辑:int y = (const)x + 1; const是常量,在编译的时候直接给出y的值
- 编译期
- 常量指针与顶层常量
- 底层(指针的内容)常量:const int ptr/ const出现在的左边:表示指针指向 const int类型
- 顶层(指针)常量:int const ptr: 指针对象不能修改,const出现在右边,表示指针类型为const
- 常量指针可以指向变量
- 常量引用
- 可以绑定变量
- 可读不可写
- 主要用于函数形参:使用引用避免传参拷贝
- 对于小的内部类型(int,bool)等,直接使用拷贝传参更合适,解引用费时且地址大小可能小于类型大小
- 可以绑定字面值
- 不可修改绑定对象
常量表达式
(如:size_t)
typedef int MyInt
- 数组的类型别名:typedef char MyCharArr[4],不直观
- using MyInt = int;(C++11)
- using MyCharArr = char[4],更直观
类型别名与指针,引用的关系
auto,需要有初始化表达式
- 常见形式
- auto:常用形式,但会类型退化
- int x1 = 3; int& ref = x; auto ref2 = ref
- 这里ref2类型退化为int,而非int&
- int x1 = 3; int& ref = x; auto ref2 = ref
- auto& 可以避免退化
- const int x=3; auto y=x;其中y退化为int,x作为右值,变为int
- const int x=3; auto& y=x; 其中y为const int&
- const auto/constexpr auto:推导出的是常量/常量表达式类型
- decltype(exp):
- 对于右值,返回exp表达式的类型,不会引入类型退化
- decltype(3.5+15l) x = 3.5+15l;
- 对左值表达式,表达式不只有名称,自动加引用
- int x=3;int* ptr =&x
- decltype(*ptr) int&
- decltype(ptr) int*
- decltype(x) int -> x 左值表达式,但只有名称
- decltype((x)) int& -> (x) 左值表达式,且不止有一个名称
- const int& y = x;
- decltype(y) int&
- int x=3;int* ptr =&x
- decltype(auto) (C++14)
- auto x = 3.5 + 15l;
- concept auto (C++20),某些类型的共同特征
域与对象的生命周期
TODO:List构建的生命周期,指向指针,指针被销毁后,list内存内是否还存在
- 对于右值,返回exp表达式的类型,不会引入类型退化
- auto:常用形式,但会类型退化