变量

编程语言 / var

本地源文件:docs/lang__var.md

变量

数据类型

C++ 的类型系统由如下几部分组成:

  1. 基础类型(括号内为代表关键词/代表类型)
  2. 无类型/void 型 (void)
  3. (C++11 起)空指针类型 (std::nullptr_t)
  4. 算术类型
  5. 整数类型 (int)
  6. 布尔类型/bool 型 (bool)
  7. 字符类型 (char)
  8. 浮点类型 (float,double)
  9. 复合类型4

布尔类型

一个 bool 类型的变量取值只可能为两种:truefalse

一般情况下,一个 bool 类型变量占有 11 字节(一般情况下,11 字节 =88 位)的空间.

Tip

可通过头文件 <climits>(C++)/<limits.h>(C) 中的宏常量 CHAR_BIT 获取字节的位数.

C 语言的布尔类型

另请参阅 C++ 与其他常用语言的区别 - bool

C 语言最初是没有布尔类型的,直到 C99 时才引入 _Bool 关键词作为布尔类型,其被视作无符号整数类型.

Note

C 语言的 bool 类型从 C23 起不再使用整型的零与非零值定义,而是定义为足够储存 truefalse 两个常量的类型.

为方便使用,stdbool.h 中提供了 bool,true,false 三个宏,定义如下:

---|---

这些宏于 C23 中移除,并且 C23 起引入 `true`,`false` 和 `bool` 作为关键字,同时保留 `_Bool` 作为替代拼写形式5.

另外,C23 起还可以通过 `<limits.h>` 中的宏常量 `BOOL_WIDTH` 获取布尔类型的位宽.

### 整数类型

用于存储整数.最基础的整数类型是 `int`.

注意

由于历史原因,C++ 中布尔类型和字符类型会被视作特殊的整型.

在几乎所有的情况下都 **不应该** 将除 `signed char` 和 `unsigned char` 之外的字符类型作为整型使用.

整数类型一般按位宽有 5 个梯度:`char`,`short`,`int`,`long`,`long long`.

C++ 标准保证 `1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)`

由于历史原因,整数类型的位宽有多种流行模型,为解决这一问题,C99/C++11 引入了 定宽整数类型.

`int` 类型的大小

在 C++ 标准中,规定 `int` 的位数 **至少** 为 1616![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 位.

事实上在现在的绝大多数平台,`int` 的位数均为 3232![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 位.

对于 `int` 关键字,可以使用如下修饰关键字进行修饰:

符号性:

  * `signed`:表示带符号整数(默认);
  * `unsigned`:表示无符号整数.

大小:

  * `short`:表示 **至少** 1616![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 位整数;
  * `long`:表示 **至少** 3232![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 位整数;
  * (C++11 起)`long long`:表示 **至少** 6464![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 位整数.

下表给出在 **一般情况下** ,各整数类型的位宽和表示范围大小(少数平台上一些类型的表示范围可能与下表不同):

类型名| 等价类型| 位宽(C++ 标准)| 位宽(常见)| 位宽(较罕见)
---|---|---|---|---
`signed char`| `signed char`| 88![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| -| -
`unsigned char`| `unsigned char`| 88![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| -| -
`short`,`short int`,`signed short`,`signed short int`| `short int`| ≥16≥16![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 1616![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| -
`unsigned short`,`unsigned short int`| `unsigned short int`| ≥16≥16![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 1616![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| -
`int`,`signed`,`signed int`| `int`| ≥16≥16![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 3232![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 1616![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)(常见于 Win16 API)
`unsigned`,`unsigned int`| `unsigned int`| ≥16≥16![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 3232![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 1616![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)(常见于 Win16 API)
`long`,`long int`,`signed long`,`signed long int`| `long int`| ≥32≥32![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 3232![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 6464![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)(常见于 64 位 Linux、macOS)
`unsigned long`,`unsigned long int`| `unsigned long int`| ≥32≥32![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 3232![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 6464![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)(常见于 64 位 Linux、macOS)
`long long`,`long long int`,`signed long long`,`signed long long int`| `long long int`| ≥64≥64![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 6464![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| -
`unsigned long long`,`unsigned long long int`| `unsigned long long int`| ≥64≥64![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 6464![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| -

当位宽为 𝑥x![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 时,有符号类型的表示范围为 −2𝑥−1 ∼2𝑥−1 −1−2x−1∼2x−1−1![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)1, 无符号类型的表示范围为 0 ∼2𝑥 −10∼2x−1![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7). 具体而言,有下表:

位宽| 表示范围
---|---
88![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 有符号:−27 ∼27 −1−27∼27−1![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7), 无符号:0 ∼28 −10∼28−1![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
1616![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 有符号:−215 ∼215 −1−215∼215−1![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7), 无符号:0 ∼216 −10∼216−1![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
3232![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 有符号:−231 ∼231 −1−231∼231−1![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7), 无符号:0 ∼232 −10∼232−1![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
6464![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 有符号:−263 ∼263 −1−263∼263−1![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7), 无符号:0 ∼264 −10∼264−1![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
等价的类型表述

在不引发歧义的情况下,允许省略部分修饰关键字,或调整修饰关键字的顺序.这意味着同一类型会存在多种等价表述.

例如 `int`,`signed`,`int signed`,`signed int` 表示同一类型,而 `unsigned long` 和 `unsigned long int` 表示同一类型.

另外,一些编译器实现了扩展整数类型,如 GCC 实现了 128 位整数:有符号版的 `__int128_t` 和无符号版的 `__uint128_t`,如果您在比赛时想使用这些类型,**请仔细阅读比赛规则** 以确定是否允许或支持使用扩展整数类型.

注意

STL 不一定对扩展整数类型有足够的支持,故使用扩展整数类型时需格外小心.

示例代码

---|---

以上示例代码存在如下问题:

  1. __int128_t f3(__int128_t) 中使用的是 C 风格的绝对值函数,其签名为 int abs(int),故 n 首先会强制转换为 int,然后才会调用 abs 函数.
  2. __int128_t f4(__int128_t) 中使用的是 C++ 风格的绝对值函数,其并没有签名为 __int128_t std::abs(__int128_t) 的函数重载,所以无法通过编译.
  3. C++ 的流式输出不支持 __int128_t__uint128_t

以下是一种解决方案:

修正后的代码

---|---

### 字符类型

分为「窄字符类型」和「宽字符类型」,由于算法竞赛几乎不会用到宽字符类型,故此处仅介绍窄字符类型.

窄字符型位数一般为 88![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 位,实际上底层存储方式仍然是整数,一般通过 [ASCII 编码](http://www.asciitable.com/) 实现字符与整数的一一对应,有如下三种:

  * `signed char`:有符号字符表示的类型,表示范围在 −128 ∼127−128∼127![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 之间.
  * `unsigned char`:无符号字符表示的类型,表示范围在 0 ∼2550∼255![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 之间.
  * `char` 拥有与 `signed char` 或 `unsigned char` 之一相同的表示和对齐,但始终是独立的类型.

`char` 的符号性取决于编译器和目标平台:ARM 和 PowerPC 的默认设置通常没有符号,而 x86 与 x64 的默认设置通常有符号.

GCC 可以在编译参数中添加 `-fsigned-char` 或 `-funsigned-char` 指定将 `char` 视作 `signed char` 或 `unsigned char`,其他编译器请参照文档.需要注意指定与架构默认值不同的符号有可能会破坏 ABI,造成程序无法正常工作.

注意

与其他整型不同,`char`、`signed char`、`unsigned char` 是 **三种不同的类型** .

一般来说 `signed char`,`unsigned char` 不应用来存储字符,绝大多数情况下,这两种类型均被视作整数类型.

### 浮点类型

用于存储「实数」(注意并不是严格意义上的实数,而是实数在一定规则下的近似),包括以下三种:

  * `float`:单精度浮点类型.如果支持就会匹配 IEEE-754 binary32 格式.
  * `double`:双精度浮点类型.如果支持就会匹配 IEEE-754 binary64 格式.
  * `long double`:扩展精度浮点类型.如果支持就会匹配 IEEE-754 binary128 格式,否则如果支持就会匹配 IEEE-754 binary64 扩展格式,否则匹配某种精度优于 binary64 而值域至少和 binary64 一样好的非 IEEE-754 扩展浮点格式,否则匹配 IEEE-754 binary64 格式.

浮点格式| 位宽| 最大正数| 精度位数
---|---|---|---
IEEE-754 binary32 格式| 3232![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 3.4 ×10383.4×1038![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 6 ∼96∼9![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
IEEE-754 binary64 格式| 6464![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 1.8 ×103081.8×10308![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 15 ∼1715∼17![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
IEEE-754 binary64 扩展格式| ≥80≥80![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| ≥1.2 ×104932≥1.2×104932![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| ≥18 ∼21≥18∼21![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
IEEE-754 binary128 格式| 128128![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 1.2 ×1049321.2×104932![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)| 33 ∼3633∼36![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)

> IEEE-754 浮点格式的最小负数是最大正数的相反数.

因为 `float` 类型表示范围较小,且精度不高,实际应用中常使用 `double` 类型表示浮点数.

另外,浮点类型可以支持一些特殊值:

  * 无穷(正或负):`INFINITY`.
  * 负零:`-0.0`,例如 `1.0 / 0.0 == INFINITY`,`1.0 / -0.0 == -INFINITY`.
  * 非数(NaN):`std::nan`,`NAN`,一般可以由 `0.0 / 0.0` 之类的运算产生.它与任何值(包括自身)比较都不相等,C++11 后可以 使用 `std::isnan` 判断一个浮点数是不是 NaN.

### 无类型

`void` 类型为无类型,与上面几种类型不同的是,不能将一个变量声明为 `void` 类型.但是函数的返回值允许为 `void` 类型,表示该函数无返回值.

### 空指针类型

请参阅指针的 [对应章节](../pointer/#空指针)

## 定宽整数类型

C++11 起提供了定宽整数的支持,具体如下:

  * `<cstdint>`:提供了若干定宽整数的类型和各定宽整数类型最大值、最小值等的宏常量.
  * `<cinttypes>`:为定宽整数类型提供了用于 `std::fprintf` 系列函数和 `std::fscanf` 系列函数的格式宏常量.

定宽整数有如下几种:

  * `intN_t`: 宽度 **恰为** 𝑁N![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 位的有符号整数类型,如 `int32_t`.
  * `int_fastN_t`: 宽度 **至少** 有 𝑁N![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 位的 **最快的** 有符号整数类型,如 `int_fast32_t`.
  * `int_leastN_t`: 宽度 **至少** 有 𝑁N![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) 位的 **最小的** 有符号整数类型,如 `int_least32_t`.

无符号版本只需在有符号版本前加一个字母 u 即可,如 `uint32_t`,`uint_least8_t`.

标准规定必须实现如下 16 种类型:

`int_fast8_t`,`int_fast16_t`,`int_fast32_t`,`int_fast64_t`,

`int_least8_t`,`int_least16_t`,`int_least32_t`,`int_least64_t`,

`uint_fast8_t`,`uint_fast16_t`,`uint_fast32_t`,`uint_fast64_t`,

`uint_least8_t`,`uint_least16_t`,`uint_least32_t`,`uint_least64_t`.

绝大多数编译器在此基础上都实现了如下 8 种类型:

`int8_t`,`int16_t`,`int32_t`,`int64_t`,

`uint8_t`,`uint16_t`,`uint32_t`,`uint64_t`.

在实现了对应类型的情况下,C++ 标准规定必须实现表示对应类型的最大值、最小值、位宽的宏常量,格式为将类型名末尾的 `_t` 去掉后转大写并添加后缀:

  * `_MAX` 表示最大值,如 `INT32_MAX` 即为 `int32_t` 的最大值.
  * `_MIN` 表示最小值,如 `INT32_MIN` 即为 `int32_t` 的最小值.

注意

定宽整数类型本质上是普通整数类型的类型别名,所以混用定宽整数类型和普通整数类型可能会影响跨平台编译,例如:

示例代码

---|---

int64_t 在 64 位 Windows 下一般为 long long int, 而在 64 位 Linux 下一般为 long int, 所以这段代码在使用 64 位 Linux 下的 GCC 时不能通过编译,而使用 64 位 Windows 下的 MSVC 时可以通过编译,因为 std::max 要求输入的两个参数类型必须相同.

此外,C++17 起在 <limits> 中提供了 std::numeric_limits 类模板,用于查询各种算数类型的属性,如最大值、最小值、是否是整形、是否有符号等.

---|---

## 类型转换

在一些时候(比如某个函数接受 `int` 类型的参数,但传入了 `double` 类型的变量),我们需要将某种类型,转换成另外一种类型.

C++ 中类型的转换机制较为复杂,这里主要介绍对于基础数据类型的两种转换:数值提升和数值转换.

### 数值提升

数值提升过程中,值本身保持不变.

Note

C 风格的可变参数域在传值过程中会进行默认参数提升.如:

示例代码

---|---

在调用 test 时,f 提升为 double,从而底层存储内容和 fd 相同,输出为

---|---

若将 `double xx = va_arg(valist, double);` 改为 `float xx = va_arg(valist, float);`,GCC 应该给出一条类似下文的警告:

---|---

此时的程序将会在输出前终止.

这一点也能解释为什么 printf%f 既能匹配 float 也能匹配 double

整数提升

小整数类型(如 char)的纯右值可转换成较大整数类型(如 int)的纯右值.

具体而言,算术运算符不接受小于 int 的类型作为它的实参,而在左值到右值转换后,如果适用就会自动实施整数提升.

具体地,有如下规则:

  • 源类型为 signed charsigned short / short 时,可提升为 int
  • 源类型为 unsigned charunsigned short 时,若 int 能保有源类型的值范围,则可提升为 int,否则可提升为 unsigned int.(C++20char8_t 也适用本规则)
  • char 的提升规则取决于其底层类型是 signed char 还是 unsigned char
  • bool 类型可转换到 intfalse 变为 0true 变为 1
  • 若目标类型的值范围包含源类型,且源类型的值范围不能被 intunsigned int 包含,则源类型可提升为目标类型.6

注意

char->short 不是数值提升,因为 char 要优先提升为 int / unsigned int,之后是 int / unsigned int->short,不满足数值提升的条件.

如(以下假定 int 为 32 位,unsigned short 为 16 位,signed charunsigned char 为 8 位,bool 为 1 位)

  • (signed char)'\0' - (signed char)'\xff' 会先将 (signed char)'\0' 提升为 (int)0、将 (signed char)'\xff' 提升为 (int)-1, 再进行 int 间的运算,最终结果为 (int)1
  • (unsigned char)'\0' - (unsigned char)'\xff' 会先将 (unsigned char)'\0' 提升为 (int)0、将 (unsigned char)'\xff' 提升为 (int)255, 再进行 int 间的运算,最终结果为 (int)-255
  • false - (unsigned short)12 会先将 false 提升为 (int)0、将 (unsigned short)12 提升为 (int)12, 再进行 int 间的运算,最终结果为 (int)-12

浮点提升

位宽较小的浮点数可以提升为位宽较大的浮点数(例如 float 类型的变量和 double 类型的变量进行算术运算时,会将 float 类型变量提升为 double 类型变量),其值不变.

数值转换

数值转换过程中,值可能会发生改变.

注意

数值提升优先于数值转换.如 bool->int 时是数值提升而非数值转换.

整数转换

  • 如果目标类型为位宽为 𝑥x 的无符号整数类型,则转换结果是原值 mod2𝑥mod2x 后的结果.
  • 若目标类型位宽大于源类型位宽:
  • 若源类型为有符号类型,一般情况下需先进行符号位扩展再转换.

  • (short)-1(short)0b1111'1111'1111'1111)转换为 unsigned int 类型时,先进行符号位扩展,得到 0b1111'1111'1111'1111'1111'1111'1111'1111,再进行整数转换,结果为 (unsigned int)4'294'967'295(unsigned int)0b1111'1111'1111'1111'1111'1111'1111'1111).
  • (short)32'767(short)0b0111'1111'1111'1111)转换为 unsigned int 类型时,先进行符号位扩展,得到 0b0000'0000'0000'0000'0111'1111'1111'1111,再进行整数转换,结果为 (unsigned int)32'767(unsigned int)0b0000'0000'0000'0000'0111'1111'1111'1111).
  • 若源类型为无符号类型,则需先进行零扩展再转换.

如将 (unsigned short)65'535(unsigned short)0b1111'1111'1111'1111)转换为 unsigned int 类型时,先进行零扩展,得到 0b0000'0000'0000'0000'1111'1111'1111'1111,再进行整数转换,结果为 (unsigned int)65'535(unsigned int)0b0000'0000'0000'0000'1111'1111'1111'1111).

  • 若目标类型位宽不大于源类型位宽,则需先截断再转换.

如将 (unsigned int)4'294'967'295(unsigned int)0b1111'1111'1111'1111'1111'1111'1111'1111)转换为 unsigned short 类型时,先进行截断,得到 0b1111'1111'1111'1111,再进行整数转换,结果为 (unsigned short)65'535(unsigned short)0b1111'1111'1111'1111).

  • 如果目标类型为位宽为 𝑥x 的带符号整数类型,则 一般情况下 ,转换结果可以认为是原值 mod2𝑥mod2x 后的结果.7

例如将 (unsigned int)4'294'967'295(unsigned int)0b1111'1111'1111'1111'1111'1111'1111'1111)转换为 short 类型时,结果为 (short)-1(short)0b1111'1111'1111'1111).

  • 如果目标类型是 bool,则是 布尔转换.
  • 如果源类型是 bool,则 false 转为对应类型的 0,true 转为对应类型的 1.

浮点转换

位宽较大的浮点数转换为位宽较小的浮点数,会将该数舍入到目标类型下最接近的值.

浮点整数转换

  • 浮点数转换为整数时,会舍弃浮点数的全部小数部分.

如果目标类型是 bool,则是 布尔转换.

  • 整数转换为浮点数时,会舍入到目标类型下最接近的值.

如果该值不能适应到目标类型中,那么行为未定义.

如果源类型是 bool,那么 false 转换为零,而 true 转换为一.

布尔转换

将其他类型转换为 bool 类型时,零值转换为 false,非零值转换为 true

定义变量

简单地说2,定义一个变量,需要包含类型说明符(指明变量的类型),以及要定义的变量名.

例如,下面这几条语句都是变量定义语句.

---|---

在目前我们所接触到的程序段中,定义在花括号包裹的地方的变量是局部变量,而定义在没有花括号包裹的地方的变量是全局变量.实际有例外,但是现在不必了解.

定义时没有初始化值的全局变量会被初始化为 00![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7).而局部变量没有这种特性,需要手动赋初始值,否则可能引起难以发现的 bug.

## 变量作用域

作用域是变量可以发挥作用的代码块.

全局变量的作用域,自其定义之处开始3,至文件结束位置为止.

局部变量的作用域,自其定义之处开始,至代码块结束位置为止.

由一对大括号括起来的若干语句构成一个代码块.

---|---

如果一个代码块的内嵌块中定义了相同变量名的变量,则内层块中将无法访问外层块中相同变量名的变量.

例如上面的代码中,输出的 𝑔g 的值将是 1010.因此为了防止出现意料之外的错误,请尽量避免局部变量与全局变量重名的情况.

常量

常量是固定值,在程序执行期间不会改变.

常量的值在定义后不能被修改.定义时加一个 const 关键字即可.

---|---

如果修改了常量的值,在编译环节就会报错:`error: assignment of read-only variable 'a'`.

## 参考资料与注释

  1. [Working Draft, Standard for Programming Language C++](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/n4917.pdf)
  2. [类型 - cppreference.com](https://zh.cppreference.com/w/cpp/language/type)
  3. C 语言的 [算术类型 - cppreference.com](https://zh.cppreference.com/w/c/language/arithmetic_types)
  4. [基础类型 - cppreference.com](https://zh.cppreference.com/w/cpp/language/types)
  5. [定宽整数类型(C++11 起)- cppreference.com](https://zh.cppreference.com/w/cpp/types/integer)
  6. William Kahan (1 October 1997).["Lecture Notes on the Status of IEEE Standard 754 for Binary Floating-Point Arithmetic"](https://people.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF).
  7. [隐式转换 - cppreference.com](https://zh.cppreference.com/w/cpp/language/implicit_conversion)
  8. [声明 - cppreference](https://zh.cppreference.com/w/cpp/language/declarations)
  9. [作用域 - cppreference.com](https://zh.cppreference.com/w/cpp/language/scope)

* * *

  1. C++20 前规定有符号整数至少要覆盖 [反码](../../math/bit/#整数与位序列) 的表示范围(即 −2𝑥−1 +1 ∼2𝑥−1 −1−2x−1+1∼2x−1−1![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)),但实际上绝大多数实现中均采用 [补码](../../math/bit/#整数与位序列) 实现;C++20 起进一步规定有符号整数必须使用补码实现.详见 [Range of values - cppreference](https://en.cppreference.com/w/cpp/language/types.html#Range_of_values). ↩

  2. 定义一个变量时,除了类型说明符之外,还可以包含其他说明符.详见 [声明 - cppreference](https://zh.cppreference.com/w/cpp/language/declarations). ↩

  3. 更准确的说法是 [声明点](https://zh.cppreference.com/w/cpp/language/scope#.E5.A3.B0.E6.98.8E.E7.82.B9). ↩

  4. 包括数组类型、引用类型、指针类型、类类型、函数类型等.由于本篇文章是面向初学者的,故不在本文做具体介绍.具体请参阅 [类型 - cppreference.com](https://zh.cppreference.com/w/cpp/language/type) ↩

  5. 参见 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3054.pdf> ↩

  6. 不包含宽字符类型、位域和枚举类型,详见 [整型转换 - cppreference](https://zh.cppreference.com/w/cpp/language/implicit_conversion#.E6.95.B4.E5.9E.8B.E8.BD.AC.E6.8D.A2). ↩

  7. 自 C++20 起生效.C++20 前结果是实现定义的.详见 [整型转换 - cppreference](https://zh.cppreference.com/w/cpp/language/implicit_conversion#.E6.95.B4.E5.9E.8B.E8.BD.AC.E6.8D.A2). ↩

* * *

>  __本页面最近更新: 2026/2/26 03:56:39,[更新历史](https://github.com/OI-wiki/OI-wiki/commits/master/docs/lang/var.md)
>  __发现错误?想一起完善?[在 GitHub 上编辑此页!](https://oi-wiki.org/edit-landing/?ref=/lang/var.md "edit.link.title")
>  __本页面贡献者:[Tiphereth-A](https://github.com/Tiphereth-A), [StudyingFather](https://github.com/StudyingFather), [orzAtalod](https://github.com/orzAtalod), [Xeonacid](https://github.com/Xeonacid), [c-forrest](https://github.com/c-forrest), [Enter-tainer](https://github.com/Enter-tainer), [Ir1d](https://github.com/Ir1d), [shuzhouliu](https://github.com/shuzhouliu), [abc1763613206](https://github.com/abc1763613206), [CamberLoid](https://github.com/CamberLoid), [CCXXXI](https://github.com/CCXXXI), [CoelacanthusHex](https://github.com/CoelacanthusHex), [Friendseeker](https://github.com/Friendseeker), [Great-designer](https://github.com/Great-designer), [Haohu Shen](mailto:haohu.shen@ucalgary.ca), [hhc0001](https://github.com/hhc0001), [ksyx](https://github.com/ksyx), [mgt](mailto:i@margatroid.xyz), [TOMWT-qwq](https://github.com/TOMWT-qwq), [ZnPdCo](https://github.com/ZnPdCo)
>  __本页面的全部内容在**[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.zh) 和 [SATA](https://github.com/zTrix/sata-license)** 协议之条款下提供,附加条款亦可能应用