变量与转换
变量
描述
变量其实只不过是程序可操作的存储区的名称。在 C++ 中,有多种变量类型可用于存储不同种类的数据,每个变量都有指定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。
变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头,大写字母和小写字母是不同的。
基本类型
整数类型(Integer Types)
int 表示整数,占用4字节
short 表示短整数,占用2字节
long 表示长整数,占用4字节
longlong 表示更长的整数,占用8字节
浮点类型(Floating-Point Types)
float 表示单精度浮点数,占用4字节
double 表示双精度浮点数,占用8字节
long double 表示更长的整数,占用8字节
字符类型(Character Types)
char 表示字符,占用1字节
char_t 表示宽字符,占用2-4字节
char16_t 表示16位Unicode字符,占用2字节
char32_t 表示32位Unicode字符,占用4字节
布尔类型(Boolean Type)
bool 用于表示布尔值,只能取
true
或false
。
以上类型的范围只是 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_char
,int
能保有其值范围则提升为int
,否则提升为unsigned_int
。bool
也可以转换到int
,false
变为$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