1.类型转换:
当我们赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示值总数取模后的余数。
比如: unsigned int i = -1;
在计算机中 负数是以补码的形式存储的。
原码:将一个数转换成二进制就是它的原码。
1的原码: 0000 0000 0000 0001
-1的原码:1000 0000 0000 0001
反码:正数的补码是本身,负数的补码是除符号位按位取反。
1的反码: 0000 0000 0000 0001
-1的反码:1111 1111 1111 1110
补码:正数是本身 负数是反码+1
1的补码: 0000 0000 0000 0001
-1的补码:1111 1111 1111 1111
-1是超出unsigned int 范围的,无符号int 可以表示的总数是[0, 0xffff) 一共2^16 个数,所以-1赋给unsigned int 的值应该是 (216-1)%216,所以-1的表示形式 是 0xffff
16位的编译器 int占16位(2个字节)
32或64位的编译器 int占32位(4个字节)
unsigned int i = -1;
printf("%u\n", i); //4294967295
printf("%d\n", i); //-1 相当于强制转换成signed
- sizeof & memset
sizeof 用来返回类型或对象所占的字节数,是一个操作符。
sizeof 三种语法形式:
- sizeof (对象)
- sizeof 对象
- sizeof (类型)
e.g.
int i;
sizeof(i); //4
sizeof i; //4
sizeof (int); //4
memset(void *buffer, int c, int count)
buffer 指针 c赋给buffer指向对象的值 count 是长度(字节数)
memset(data, 0x0f, sizeof(data))
data[0] : 0000 0001 0000 0001 0000 0001 0000 0001
3.引用 & 指针
- 我们所说的引用,指的是左值引用。相当于给对象起了另外一个名字。
- 不能用常量对引用进行初始化。即 int &data = 9是错误的。
指针与引用的区别
指针是一个对象,而引用是别名。
指针可以不赋初值,引用不可以。
指针可以在其生命周期内指向不同的对象,引用只能在它初始化的时候赋值。
野指针
野指针是指指向了一块随机的内存空间,不受程序控制。如指针指向已经被删除的对象或者指向一块没有访问权限的内存空间,之后再对其解引用。
产生原因:
- 指针定义时未被初始化(static修饰的指针变量会被置空)
- 指针释放的时候没有被置空。
- 指针操作超越变量作用域。
void* 指针
void* 是一种特殊的指针类型,可用于存放任意对象的地址。利用void* 指针能做的事儿也比较有限:拿它和别的指针比较、作为函数的输入输出,或者赋给另一个void*指针。
指向指针的引用
int i = 42;
int *p;
int *&r = p //r是一个指向指针的引用。
r = &i;
r = 0;
4.const限定符
- 因为const对象一旦创建后其值就不能再改变,所以const必须初始化(引用也是)
- 如果想在多个文件之间共享const 对象,必须在变量的定义之前添加extern关键字。
- 非常量可以转换成const;
int i = 42;
const int &r1 = i; //允许将const int & 绑定到一个普通int 对象上
const int &r2 = 42; //正确:r2是一个常量引用
const int &r3 = r1 * 2; //正确: r3是一个常量引用
int &r4 = r1 * 2; //错误:不能用非常量来绑定一个常量。
int i = 43;
const int *p = &i; //p是一个指针 指向整型常量 p指的对象的值不变(底层const)
int *const p = &i; //p是一个常量指针 指向整型 p永远指向i (顶层const)
const int* const p = &i; //p是一个常量指针 指向整型常量
5.constexpr和常量表达式
- 常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。
const int max_files = 20;
-
将变量声明为constexpr,编译器可以来验证变量值是否是一个常量表达式。
-
在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效。
constexpr int mf = 20;
constexpr int limit = mf + 1;
constexpr int sz = get_size(); //编译器报错
const int *p = nullptr;
constexpr int *q = nullptr; //q是一个指向整型的常量指针
6.typedef(类型别名) & using (别名声明)
typedef long long LL;
using LL = long long;
7.decltype类型指示符 & auto
-
auto会忽视顶层const, 底层const被保留下来。decltype都会保留下来。
-
decltype的结果类型与表达式形式密切相关。如果给变量加上了一层或多层括号,编译器会把它当成是一个表达式。变量是一种可以作为赋值语句左值得特殊表达式,所以这样的decltype就会得到引用类型。
-
表达式的内容是解引用操作,decltype将得到引用类型。
-
赋值也会产生引用;
int i = 42, *p = &i;
decltype(*p) c; //错误, c是int&, 必须初始化
decltype((i)) d; //错误:d是int&, 必须初始化
decltype(i) e; e是一个未初始化的int
decltype(a = b) c;//错误, c是int&, 必须初始化 a并没有真的等于b