看了一遍就忘记的《C++ Primer》

约定: 笔者写此文只是记录C++语言学习中遇到的自认为需要反复记忆的内容;

1.算术类型

起因:VS2019下测试 long 四个字节,linux中测试 long 八个字节
为什么? 因为编译器可以根据硬件特性自主选择适合的长度。

算术类型分为两类:整型(包括字符和布尔类型在内) 和 浮点型。
C++标准只规定了尺寸的最小值,但同时允许编译器赋予这些类型更大的尺寸。
先别着急看表格,记住几句话:C++语言规定

  • 一个 int 至少和一个 short 一样大
  • 一个 long 至少和一个 int 一样大
  • 一个 long long 至少和一个 long 一样大
类型 最小尺寸
bool 未定义
char 8位 1字节
wchar_r 16位 2字节
char16_t 16位 2字节
char32_t 32位 4字节
shrot 16位 2字节
int 16位 2字节
long 32位 4字节
long long (C11标准规定的类型) 64位 8字节
float 6位有效数字
double 10位有效数字
long double 10位有效数字

2.字和字节

可寻址的最小内存块称为 “字节(byte)”
存储的基本单元称为 “字(word)”
  • 大多数机器的字节由 8 比特够成
  • 字则由 32 或 64 比特够成,也就是 4 或 8 字节

3.带符号的 和 无符号的

  • 带符号类型可以表示正数,负数或0
  • 无符号类型只能表示大于等于0的 值
类型 int,short long 和long long 都是带符号的;
如果别人问:你怎么知道的? 《C++ Primer》第五版 第31页倒数第二行第一句话。
  • 与其他整型不同,字符型被分为了三种:char,signed char 和 unsigned char
    这里需要注意的是:只写 char 类型,则是隐式的,实际有无符号取决于编译器

4.如何选择类型

笔者认为类型是需要掌握的,我不想只得到她的人,我还想得到她的心。
  • 当明确知晓数值不可能为负时,选用无符号类型
  • 使用 int 执行整数运算。如果你的数值超过了 int 的表示范围,选用 long long。
  • 算术表达式中不要使用 char 或 bool,只有在存放字符或布尔值时才使用它们。
    因为 char 类型在某些机器是有符号的,在另一些机器上又是无符号的,所以运算特别容易出错;
    如果你需要使用一个不大的整数,那么明确指定它的类型是 signed char 或者 unsigned char
  • 执行浮点数运算选用double。
    这是因为float通常精度不够而且双精度浮点数和单精度浮点数的计算代价相差无几。
    事实上,对于某些机器来说,双精度运算甚至比单精度还快。
    long double 提供的精度在一般情况下是没有必要的,况且它带来的运行时消耗也不容忽视。

5.类型转换

  • 赋给无符号类型一个超出它表示范围的值时
    结果是初始值对无符号类型表示数值总数取模后的余数

例如 8 比特大小的 unsigned char 可以表示 0-255 区间内的值
如果赋给超过 255 的值给它,实际打印的结果是该值对 256 取模后所得的余数
如上是《C++ Primer》33页原话, 我对这个余数是真的不明白,原书没写明

那只能用自己的方法先来解释一下为何 255:
ok 还原现场:我如何来理解那句话,先不管,先用代码实现,测试结果的确是255
unsigned char aaa = -1;
printf("%d\n", aaa); //结果255
printf("%d\n", (-1) % 256) //结果-1

然后来解释到底发生了什么:
最开始 -1 这个负数在机器中以补码的形式存在,
当它赋值给 unsigned char 类型时发生类型转换, -1 在赋值时是 unsigned char 类型
对应二进制是 1111 1111 将这个值赋给了 aaa,然后10进制打印出 就是 255
这是笔者的理解,查阅了一些资料,发现一些大佬对此余数进行了解释。

笔者将此方法贴在此处,感谢博主分享。但笔者仍选择了上述 补码 的理解方法。

有整数a和b,a对b进行取模或取余运算
1、求整数商:c=a/b
取模运算在计算商值向负无穷方向舍弃小数位
取余运算在计算商值向0方向舍弃小数位
2、计算模或者余数:r=a-(c*b)
注:取模运算遵循尽可能让商小,取余运算遵循尽可能让余数的绝对值小。因此,取模和取余的结果不同。

mod为取模,rem为取余,取模和取余所得的结果在a和b(同为整数) 符号相同 的时候是相等的
当a和b符号一致时,求模运算和求余运算所得的c的值一致,因此结果一致。
但是当符号不一致的时候,结果不一样。

具体来说,求模运算结果的符号和b一致,求余运算结果的符号和a一致。
在本例中,将-1和256带入a和b,c=-1/256,向负无穷方向舍弃小数得-1,计算得r=255.

字面值常量

形如 42 的值被称作字面值常量;记住如下几句话!

1.默认情况下,十进制字面值是带符号数,八进制和十六进制都有可能;
2.十进制字面值的类型是 int, long 和 long long 中尺寸最小的那个,前提是这个类型能容纳这个值。
八和十六进制则是能容纳其数值的 int,unsigned int,long ,unsigned long
和long long,unsigned long long的尺寸最小者
3.short没有对应的字面值
4.默认的,浮点型字面值是一个double
别人问,你怎么知道的 ?《C++ primer》第五版 35和36页 写的清清楚楚;

5. ‘a’ 实际是 字符字面值;“hello” 实际上是字符串字面值,是一个由常量字符构成的数组而且末尾有 ‘\0’

术语:何为对象?

  • 通常,对象 是指一块能存储数据并具有某种类型的内存空间。

初始化 和 赋值 是两个完全不同的操作

  • 初始化的含义是创建变量时赋予其一个初始值。
  • 赋值的含义是把对象的当前值擦除,而以一个新值来替代。
  • 严格来说,编译器并未被要求检查此类未初始化变量的错误,所以声明变量请直接初始化

关键字extern

  • 如果想声明一个变量而非定义它,加关键字extern
  • extern放在变量或者函数之前,表示变量或者函数的定义在别的文件中,
    提示编译器遇到此变量和函数时在其他模块中寻找其定义。
  • 但是 只能声明这个变量而不能定义它,且不要显式地初始化变量;比如
extern int i; //声明i二非定义 i
int j;		//声明并定义 j
  • 包含显示初始化地任何声明 都称为 定义 了,抵消了 extern 的作用

  • 变量 能且只能被定义一次,但是可以被多次声明。

  • 如果要在多个文件夹中使用同一个变量,就必须将声明和定义分离。
    此时变量的定义必须出现在且只能出现在一个文件中,
    而其他用到该变量的文件必须对其进行声明却绝对不能重复定义

  • 《C++ primer》第五版 41页

C++ 是一种静态类型语言

  • 含义是在编译阶段检查类型。 这一过程称为 类型检查。

作用域

  • 作用域中一旦声明了某个名字,它所嵌套的所有作用域中都能访问改名字
    且同时允许在内层作用域中重新定义外层作用域已有的名字。
  • 记一个例子
	int i = 100, sum = 0;
	for (int i = 0; i != 10; ++i)
		sum += i;
	cout << i << " " << sum << endl;

检测过 不报错,输出 100 45

引用必须被初始化

  • 引用本身不是一个对象,所以不能定义引用的引用。

NULL 是 预处理变量 nullptr 是 字面值

《C++ permier》 49页 库函数定义了NULL,值为0;
C11标准下测试后不加头文件也能编译通过

赋值永远改变的是等号左侧的对象

指针 和 引用 的主要区别

  • 说法一
使用引用(reference)和指针(pointer)都可以间接访问一个值,但它们之间存在两个重要的区别:
1. 引用总是指向某个确定的对象,定义引用时没有进行初始化会出现编译错误;
2. 赋值行为上存在差异:给引用赋值修改的是该引用所关联的对象的值,引用一经初始化,
就始终指向同一个特定对象。给指针赋值修改的是指针对象本身,也就是使指针指向另一个对象,
指针在不同时刻可指向不同的对象。
  • 说法二
3. 指针是一个实体,而引bai用仅是个别名;
4. 引用使用du时无需解引zhi用(*),指针需要解引用;
5. 引用只能在定义时dao被初始化一次,之后不可变;指针可变;
引用“从一而终” ^_^
6. 引用没有 const,指针有 const,const 的指针不可变;
7. 引用不能为空,指针可以为空;
8. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身
9. (所指向的变量或对象的地址)的大小;
typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,
但是当引用作为类成员名称时,其占用空间与指针相同4个字节(没找到标准的规定)。
10. 指针和引用的自增(++)运算意义不一样;

面对一条比较复杂的指针 或 引用 使用 右左原则;

如果想在多个文件之间共享const对象,必须在变量的定义之前添加extern关键字。

常量引用 就是对const的引用

引用的类型必须与其所引用对象的类型一致,但是有两例外

  • 1.初始化常量引用时允许用任意表达式作为初始值,只要类型能强转为对象类型即可
  • 2.对const的引用可能引用一个并非const的对象 举例如下:
int i = 42;
int &r1 = i;				//引用 r1 绑定对象 i 
const int &r2 = i;		//r2也绑定对象 i,但是不允许通过 r2修改 i 的值
r1 = 0;						// r1 并非常量,i 的值修改为 0
r2 =0;						// 错误:r2 是一个常量引用

指向常量的指针仅仅要求不能通过该指针改变对象的值,而没有规定那个对象的值不能通过其他途径改变

猜你喜欢

转载自blog.csdn.net/GameStrategist/article/details/107525155