变量与转换

变量

描述

变量其实只不过是程序可操作的存储区的名称。在 C++ 中,有多种变量类型可用于存储不同种类的数据,每个变量都有指定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。

变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头,大写字母和小写字母是不同的。

基本类型

整数类型(Integer Types)

  1. int 表示整数,占用4字节

  2. short 表示短整数,占用2字节

  3. long 表示长整数,占用4字节

  4. longlong 表示更长的整数,占用8字节

浮点类型(Floating-Point Types)

  1. float 表示单精度浮点数,占用4字节

  2. double 表示双精度浮点数,占用8字节

  3. long double 表示更长的整数,占用8字节

字符类型(Character Types)

  1. char 表示字符,占用1字节

  2. char_t 表示宽字符,占用2-4字节

  3. char16_t 表示16位Unicode字符,占用2字节

  4. char32_t 表示32位Unicode字符,占用4字节

布尔类型(Boolean Type)

  1. bool 用于表示布尔值,只能取truefalse

以上类型的范围只是 C++ 标准规定的最小要求,实际上,许多系统上这些类型可能占用更多的字节,例如,很多现代计算机上 int 通常占用 4 字节,而 long 可能占用 8 字节。

定义变量

变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。

int a = 20;

//type variable_name = value;

这是一个最基本的例子。其中,

  • int:数据类型

  • a:变量名

  • 20:值

下面是一些有效声明变量的例子:

int i, j, k;
char c, ch;
float f;
double d;

变量也可以在声明的时候初始化,也就是给定一个值,比如:

extern int number = 1;  //其中,通过extern,可以使变量跨文件读取。
int j = 5, k = 2;
byte b = 22;
char name = 'x';

变量作用域

在目前我们所接触到的程序段中,定义在花括号包裹的地方的变量是局部变量,而定义在没有花括号包裹的地方的变量是全局变量。其中,全局变量的作用域为定义开始到文件结束,而局部变量为定义开始到代码块结束。

定义时没有初始化值的全局变量会被初始化为0。而局部变量没有这种特性,需要手动赋初始值,否则可能引起难以发现的 bug。如果一个代码块的内嵌块中定义了相同变量名的变量,则内层块中将无法访问外层块中相同变量名的变量。

int g = 20;  // 定义全局变量

int main() {
  int g = 10;         // 定义局部变量
  printf("%d\n", g);  // 输出 g
  return 0;
}

此段代码会输出10,所以在实战过程中要尽量避免这种问题。

常量

常量是固定值,在程序执行期间不会改变,在定义后无法被修改。

通过在定义时添加const关键字。

const int a = 2;

实例:定义变量

要求:定义变量a = 1, b = 2,并输出a+b的结果。

代码如下:

#include <iostream>
using namespace std;

int main(){
    int a = 1, b = 2;
    cout << a+b << endl;
    return 0;
}

数据转换

类型转换是将一个数据类型的值转换为另一种数据类型的值。C++ 中有四种类型转换:静态转换、动态转换、常量转换和重新解释转换。

左值(Lvalues)和右值(Rvalues)

左值(lvalue):指向内存位置的表达式被称为左值(lvalue)表达式。左值可以出现在赋值号的左边或右边。

右值(rvalue):术语右值(rvalue)指的是存储在内存中某些地址的数值。右值是不能对其进行赋值的表达式,也就是说,右值可以出现在赋值号的右边,但不能出现在赋值号的左边。

变量是左值,因此可以出现在赋值号的左边。数值型的字面值是右值,因此不能被赋值,不能出现在赋值号的左边。

(类型)转换规则

整数提升

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

  • char的提升规则取决于其底层的类型:如果是signed_char,则提升为int;如果是unsigned_charint能保有其值范围则提升为int,否则提升为unsigned_int

  • bool也可以转换到intfalse变为$0$,true变为$1$。

  • short也可以提升为int

浮点提升

位宽较小的浮点数(如float)可以提升为位宽较大的浮点数(如double),其值不变。

(数值)转换规则

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

整数转换

符号扩展(Sign Extension):对于有符号整数类型,当从较小范围的有符号类型转换为较大范围的有符号类型时,符号位会被扩展。例如,int8_t a = -1; int32_t b = a;,这里a的-1表示为0xFF,转换为int32_t时会进行符号扩展,高位用1填充,因此得到0xFFFFFFFF。

零扩展(Zero Extension):如果源类型是无符号类型,则会进行零扩展,高位全部填充为0。例如,uint8_t x = 255; uint32_t y = x;,这里高位用0填充,结果为0x000000FF。

截断(Truncation):当较大范围的整数类型转换为较小范围的整数类型时,可能会发生数据截断。例如,long a = 100000L; int b = (int)a;,这里高位部分会被截掉,可能导致数据丢失。

浮点转换

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

浮点整数转换

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

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

布尔转换

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

转换方法

以下都为 显式转换。而隐式转换在之前便出现过了,如:

  • 变量的赋值

  • 算数运算 还有函数调用等等。

显式转换需要明确指定,而隐式转换是由编译器自己执行的。

静态转换(Static Cast)

静态转换是将一种数据类型的值强制转换为另一种数据类型的值。静态转换通常用于比较类型相似的对象之间的转换,例如将 int 类型转换为 float 类型。静态转换不进行任何运行时类型检查,因此可能会导致运行时错误。

int i = 10;
float f = static_cast<float>(i); // 静态将int类型转换为float类型

动态转换(Dynamic Cast)

常量转换(Const Cast)

常量转换用于将 const 类型的对象转换为非 const 类型的对象,只能用于转换掉 const 属性,不能改变对象的类型。

const int i = 10;
int& r = const_cast<int&>(i); // 常量转换,将const int转换为int

重新解释转换(Reinterpret Cast)

重新解释转换将一个数据类型的值重新解释为另一个数据类型的值,通常用于在不同的数据类型之间进行转换,它不进行任何类型检查,因此可能会导致未定义的行为。

int i = 10;
float f = reinterpret_cast<float&>(i); // 重新解释将int类型转换为float类型

Last updated