C++ Primer 笔记-第2章 变量和基本类型

Code有毒
发布于

2.1 基本内置类型

2.1.1 算数类型

  1. 一个 char 的空间应确保可以存放机器基本字符集中任意字符对应的数字值,其大小和机器字节一样。
  2. wchar_t 类型用于确保可以存放机器最大扩展字符集中的任意一个字符,类型 char16_tchar32_t 则为 Unicode 字符集服务(Unicode 是用于表示所有自然语言中字符的标准)。
  3. 大多数计算机以 2 的整数次幂个比特 bite 作为块来处理内存,可寻址的最小内存块称为字节 byte,存储的基本单元称为字 word,它通常由几个字节组成。
  4. 大多数机器的字节由 8 个比特构成(1byte == 8bite
  5. 32位:1word == 4byte == 32bite
  6. 64位:1word == 8byte == 64bite
  7. 为了赋予内存中某个地址明确的含义,必须首先知道存储在该地址的数据的类型。类型决定了数据所占的比特数以及该如何解释这些比特的内容。
  8. 通常 float: 1word(32bite)、double: 2word(64bite)、long double: 3或4word(96或128bite)

2.1.2 类型转换

  1. 当我们赋值给无符号类型一个超过它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。(a = b x q + r,其中 |r|<|a|。负数取模:r = a - (a / b) x b, 其中 a/b 在 C++ 中是向0取整)
  2. 当我们赋给带符号类型一个超出它表示范围的值时,结果是未定义的,程序可能继续工作、可能崩溃、也可能生成垃圾数据。
  3. 程序应该尽量避免依赖与实现环境的行为。
  4. 切勿混用带符号类型和无符号类型。

2.1.3 字面值常量

  1. 我们可以将整型字面值写作十进制、八进制、十六进制数的形式。以 0 开头的整数代表八进制,以 0x 或者 0X 开头的代表十六进制数。
  2. 如果一个字面值连与之关联的最大的数据都放不下,将产生错误。类型 short 没有对应的字面值。
  3. 由单引号括起来的一个字符称为 char 型字面值,双引号括起来的零个或多个字符则构成字符串型字面值。
  4. 如果两个字符串字面值位置紧邻且仅由空格、缩进和换行符分隔,则它们实际上是一个整体。
  5. 转义序列 escape sequence

2.2 变量

2.2.1 变量定义

  1. 初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值替代。

2.2.2 变量声明和定义的关系

  1. 如果想声明一个变量而非定义它,就在变量名前添加关键字 extern,而且不要显式地初始化变量。
  2. 如果要在多个文件中使用同一个变量,就必须将声明和定义分离。此时,变量的定义必须出现在且只能出现在一个文件中,而其他用到该变量的文件必须对其进行声明,却绝对不能重复定义。

2.2.3 标识符

  1. 用户自定义的标识符中不能连续出现两个下画线,也不能以下画线紧连大写字母开头。此外,定义在函数体外的标识符不能以下画线开头。

2.3 复合类型

2.3.1 引用

  1. 区分左值引用 lvalue reference 和右值引用 rvalue reference
  2. 引用本身不是一个对象,所以不能定义引用的引用。
  3. 引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起。

2.3.2 指针

  1. 因为引用不是对象,没有实际地址,所以不能定义指向引用的指针。

  2. NULL 为预处理变量,这个变量在头文件 cstdlib 中定义,它的值就是 0

  3. 在 C++11 新标准下,最好使用 nullptr,同时尽量避免使用 NULL

  4. void* 是一种特殊的指针类型,可用于存放任何对象的地址。

  5. 利用 void* 指针能做的事:

    (1)拿它和别的指针比较

    (2)作为函数的输入或输出

    (3)赋给另外一个void* 指针。

  6. 无法访问和操作 void* 内存空间中所存的对象。

2.3.3 理解复合类型的声明

  1. 面对一条比较复杂的指针或者引用的声明语句时,从右向左阅读有助于弄清楚它的含义。如:
int *p;
int *&r = p;    // r是一个指向指针p的引用。

2.4 const限定符

  1. 利用一个对象去初始化另外一个对象,则它们是不是 const 都无关紧要。
  2. 默认情况下, const 对象被设定为仅在文件内有效。当多个文件中出现了同名的 const 变量时,其实等同于在不同的文件中分别定义了独立的变量。
  3. 如果想在多个文件之间共享 const 对象,必须在变量的定义之前添加 extern 关键字。

2.4.2 指针和const

  1. 指向常量的指针 pointer to const
const double pi = 3.14;
const double * cptr = &pi;
  1. 常量指针 const pointer:把 *放在 const 之前用以说明指针是一个常量,即不变的是指针本身的值而非指向的那个值。
int errNumb = 0;
int *const curErr = &errNumb;
  1. 指向常量对象的常量指针:
const double pi = 3.14;
const double *const pip = &pi;

2.4.3 顶层 const

  1. 一般的来说,顶层 const 可以表示任意的对象是常量。底层 const 则与指针和引用等复合类型的基本类型部分有关。
  2. 比较特殊的是,指针类型既可以是顶层 const(top-level const) 也可以是底层 const(low-level const)。顶层 const 表示指针本身是一个常量,底层 const 表示指针所指的对象是一个常量。(int *const 顶层,const int* 底层)
  3. 当执行对象拷贝操作时,是否为顶层 const 不影响拷贝。
  4. 当执行对象拷贝操作时,拷入和拷出的对象都必须具有相同的底层 const 资格,或者两个对象的数据类型必须能够转换(非常量可以转换成常量,反之则不行)。

2.4.4 constexpr和常量表达式

  1. 常量表达式 const expression 是指值不会改变并且在编译过程中就能得到计算结果的表达式。
  2. constexpr 会把它所定义的对象置为顶层 const,即常量对象。
  3. 尽管指针和引用都能定义成 constexpr,但是它们的初始值却受到严格的限制。一个 constexpr 指针的初始值必须是 nullptr 或者 0,或者存储于某个固定地址的对象。
  4. constexpr 声明中如果定义了一个指针,限定符 constexpr 仅对指针有效,对指针所指的对象无关。

2.5 处理类型

2.5.1 类型别名

  1. 传统方法 typedef
typedef double base, *p;    // base是double的同义词,p是double*的同义词
  1. 新规范使用别名声明 alias declaration
using SI = Sales item;
  1. 如果某个类型别名指代的是复合类型或者常量:
typedef char *pstring;
const pstring cstr = 0;     //cstr是指向char的常量指针,等同于char* const cstr = 0;
const pstring *ps;          // ps是一个指针,它的对象是指向char的常量指针

2.5.2 auto类型说明符

  1. auto 一般会忽略掉顶层 const,同时底层 const 则会保留下来。
  2. 设置一个类型为 auto 的引用时,初始值中的顶层常量属性仍然保留。如果我们给初始值绑定一个引用,则此时的常量就不是顶层常量了。(此规则理解不清晰)

2.5.3 decltype类型指示符

  1. 如果希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量,使用 decltype(选择并返回操作数的数据类型)。

  2. decltype(*p) 结果类型是 int&,而非 int

int i = 0, *p = &i;
decltype(*p) z = i;
  1. 对于 decltype 所用的表达式来说,如果变量名加上一对括号,得到的类型于不加括号时会不一样:
// 不加括号,得到的结果就是该变量的类型:
decltype(i) e = 0;      // e是int

// 加括号,编译器会把它当作一个表达式,变量是一种可以作为赋值语句左值的特殊表达式,所以会得到引用类型:
decltype((i)) e = i;    // d是int&(加括号时,结果永远是引用)

2.6 自定义数据结构

2.6.1 定义Sales_data类型

  1. 不能使用圆括号进行类内初始化。

2.6.3 编写自己的头文件

  1. 预处理变量无视 C++ 中作用域的规则。

原文

1
评论
收藏 1