[C++] 基础知识之2、C++中的基本数据类型

C++中的基本数据类型

虽然C++中的基本数据类型很常用,但是如果熟视无睹,往往在编程实践中容易出错。这里总结出来,希望能够让自己和别人加深印象。

存储空间

C++标准规定的是每个算数类型的最小存储空间,但其并不阻止编译器用更大的存储空间。下面是大多数编译器所采用的存储空间。

类型范围
void0
bool1 [ 0 , 1 ] [0,1] [0,1]
(signed) char1 [ − 2 7 , 2 7 − 1 ] [-2^7, 2^7-1] [27,271]
unsigned char1 [ 0 , 2 8 − 1 ] [0, 2^8-1] [0,281]
(signed) short2 [ − 2 15 , 2 15 − 1 ] [-2^{15},2^{15}-1] [215,2151]
unsigned short2 [ 0 , 2 16 − 1 ] [0, 2^{16}-1] [0,2161]
(signed) int ≥ s i z e o f ( s h o r t ) \ge sizeof(short) sizeof(short)与操作系统的字长有关
unsigned int ≥ s i z e o f ( s h o r t ) \ge sizeof(short) sizeof(short)与操作系统的字长有关
_int81 [ − 2 7 , 2 7 − 1 ] [-2^7, 2^7-1] [27,271]
_int162 [ − 2 15 , 2 15 − 1 ] [-2^{15},2^{15}-1] [215,2151]
_int324 [ − 2 31 , 2 31 − 1 ] [-2^{31},2^{31}-1] [231,2311]
_int648 [ − 2 63 , 2 63 − 1 ] [-2^{63},2^{63}-1] [263,2631]
(signed) long ≥ m a x ( 32 , s i z e o f ( i n t ) ) \ge max(32,sizeof(int)) max(32,sizeof(int))与操作系统的字长有关
unsigned long ≥ m a x ( 32 , s i z e o f ( i n t ) ) \ge max(32, sizeof(int)) max(32,sizeof(int))与操作系统的字长有关
(signed) long long8 [ − 2 63 , 2 63 − 1 ] [-2^{63},2^{63}-1] [263,2631]
unsigned long long8 [ 0 , 2 64 − 1 ] [0,2^{64}-1] [0,2641]
float4 ± 3.4 e + / − 38 \pm3.4e^{+/-38} ±3.4e+/38 (7位)
double8 ± 1.7 e + / − 308 \pm1.7e^{+/-308} ±1.7e+/308 (15位)
long double8 ± 1.7 e + / − 308 \pm1.7e^{+/-308} ±1.7e+/308 (15位)
enum*与操作系统的字长有关
wchar_t2 [ 0 , 2 16 − 1 ] [0,2^{16}-1] [0,2161]

通常情况下,指针P的大小同int的大小,也是和操作系统字长有关。关于数据类型的存储空间大小,需要注意的问题包括:

  1. bool和wchar_t是C++语言特有的。由于许多外文字符的数量超过了unsigned char的表示范围,所以C++定义了wchar_t来表示外文字符集。在有些编译器上,wchar_t的长度被定义为4个字节。
  2. 除上表之外,C/C++还可以自定义枚举enum,联合union和struct结构体类型,其中enum类型的数据所占用的字节数也由操作系统和编译平台决定,通常情况下和int相同。
  3. int和long类型数据的字节数和数值范围由操作系统和编译平台决定。比如在16位机上,sizeof(int) = 2,而32位机上的sizeof(int) = 4;32位机上的sizeof(long) = 4,而64位机上sizeof(long) = 8。除此之外,64位机上的pointer占8个字节。
  4. 如果考虑可移植性,建议尽量使用_int8, _int16, _int32和_int64等,这可以保证在不同操作系统和编译平台上开辟的空间大小一致。

类型转换

不同类型的数据之间有可能通过操作符进行运算,为了保证一致性,C++中存在隐式的算术转换,例如加法或者乘法的两个操作数被提升为共同的类型,然后再用它表示结果的类型。两个通用的指导原则如下:

  1. 为防止精度损失,如果必要的话,类型总是被提升为较宽的类型(也就是上表中占用字节多的类型)。
  2. 所有含有小于整型的有序类型的算术表达式在计算之前其类型都会被转换为整型(这一点往往容易被大家忽略)。但是long类型的一般转换有一个例外:如果一个操作数是long类型而另一个是unsigned int类型,那么只有机器上的long类型的长度足以存放unsigned int的所有值时(一般来说,在32位操作系统中long类型和int类型都用一个字长表示,所以不满足这里的假设条件),unsigned int才会被转换为long类型,否则两个操作数都被提升为unsigned long类型。若两个操作数都不是long类型,而其中一个是unsigned int,那么另一个也被转换为unsigned int,否则两个操作数一定都是int类型(因为已经被提前提升了)。

左值右值

在C++11中,所有的值必属于左值、右值两者之一,其中右值又可以细分为纯右值、将亡值(在C++98中右值只有纯右值)。我们下面分别进行解释。

  1. 左值和右值:可以取地址的、有名字的就是左值;反之,不能取地址的、没有名字的就是右值(将亡值或者纯右值)。举个例子,int a = b + c,其中a就是左值,因为其有变量名a,通过&a可以得到该变量的地址;表达式b+c,函数int func()的返回值是右值,因为在其被赋值给某一变量之前,我们不能通过变量名找到它,&(b+c)这样的操作不会通过编译。
  2. 纯右值和将亡值:C++98中的右值只有纯右值,指的是临时变量值、不跟对象关联的字面量值。临时变量指的是非引用返回的函数返回值、表达式等,例如函数int func()的返回值,表达式a+b;不跟对象关联的字面量值,例如true,2,”C”等常量值。在C++11中纯右值的概念等同于C++98中的纯右值。
    C++11对C++98的右值概念进行了扩充,增加了将亡值(xvalue,eXpiring Value)。它指的是跟右值引用相关的表达式,这样的表达式通常是将要被移动的对象(移为它用),比如返回右值引用T&&的函数返回值、std::move的返回值,或者转换为T&&的类型的转换函数的返回值。将亡值可以理解为通过“盗取”其他变量内存空间的方式获取到的值。在确保其他变量不再被使用、或即将被销毁时,通过“盗取”的方式可以避免内存空间的释放和分配,能够延长变量值的生命周期。
  3. 左值引用和右值引用:左值引用就是对一个左值进行引用的类型。右值引用就是对一个右值进行引用的类型。
    右值引用和左值引用都是属于引用类型。无论是声明一个左值引用还是右值引用,都必须立即进行初始化。而其原因可以理解为是引用类型本身自己并不拥有所绑定对象的内存,只是该对象的一个别名。左值引用是具名变量值的别名,而右值引用则是不具名(匿名)变量的别名。
    左值引用通常也不能绑定到右值,但常量左值引用是个“万能”的引用类型。它可以接受非常量左值、常量左值、右值对其进行初始化。不过常量左值所引用的右值在它的“余生”中只能是只读的。相对地,非常量左值只能接受非常量左值对其进行初始化。
int &a = 2;       // 左值引用绑定到右值,编译失败
int b = 2;        // 非常量左值
const int &c = b; // 常量左值引用绑定到非常量左值,编译通过
const int d = 2;  // 常量左值
const int &e = c; // 常量左值引用绑定到常量左值,编译通过
const int &b =2;  // 常量左值引用绑定到右值,编程通过

右值引用通常不能绑定到任何的左值。要想绑定一个左值到右值引用,通过需要std::move()将左值强制转换为右值,例如:

int a;
int &&r1 = c;             // 编译失败
int &&r2 = std::move(a);  // 编译通过

只要能够绑定右值的引用类型,都能够延长右值的生命周期。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值