第三章:对象与基本类型(一)

初始化与赋值语句

初始化/赋值语句是程序中最基本的操作,其功能是将某个值与一个对象关联起来,典型的例子如下

int x = 10;	// 初始化
x = 20;		// 赋值

其中的范围比较广泛,可以是字面值对象(变量或常量)所表示的值等 。而对于对象我们使用标识符来描述,标识符分为:常量变量引用等。

值和对象都是有着对应的类型的,比如10也有着类型。

相比起赋值语句,初始化语句需要额外进行一些操作,包括:

  • 在内存中开辟空间,保存对应的数值
  • 在编译器中构造符号表,将标识符与相关内存空间关联起来

在使用初始化和赋值语句时我们要注意,其中可能涉及到类型转换。比如

int x = 10.5

就涉及到了从doubleint的类型转换。

类型详述

基础

类型是一个编译期的概念,可执行文件中不存在类型的概念。类型存在于C++内部,而C++本身也是一个强类型语言。在C++中引入类型的目的是为了更好地描述程序,防止误用。

C++中的类型主要描述了以下信息:

  • 存储所需要的尺寸,可以用sizeof来查看具体类型对应的尺寸,在标准中并没有严格限制类型的尺寸。

    不限制主要是出于性能的考虑,在不同位数的机器上单次处理的数据位数不同,所以对应的类型尺寸也是不同的

  • 取值空间,可以使用std::numeric_limits来进行查看,超过取值空间可能会产生溢出
    std::cout << std::numeric_limits<int>::min();
    std::cout << std::numeric_limits<int>::max();
    
  • 对齐信息:数据在内存中存储的首地址一定是对齐信息的整数倍,这是为了从内存读取到cache line时候可以一次读取完整的类型对应的数据,在C++中可以使用alignof来查看对齐信息
    std::cout << alignof(int);
    

    对于结构体来说,会根据内部的类型各自的对齐信息来调整整个结构体的尺寸,比如一个4字节的int和一个1字节的char最后的结构体大小为8而不是5。

  • 可以支持的操作

C++ 中支持的类型可以划分为基本类型和复杂类型。基本类型也叫内建类型指的是C++语言中所支持的类型,主要包括:

  • 数值类型
    • 字符类型:char,wchar_t,char16_t,char32_t

    char一般用来表示ASCII码,wchar_t一般是两个字节,char16_tchar32_t一般用来表示Unicode编码

    • 整数类型:
      1. 带符号整数类型:short,int,long,long long

        各个类型的差异主要是尺寸不同,也就是取值区间不同

      2. 无符号整数类型:unsigned + 带符号整数类型

        这里要注意单独的unsigned表示的是unsigned int

    • 浮点类型:float,double,long double
  • void

而复杂类型指的是由基本类型组合、变种所产生的类型,可能是标准库引入或者自定义类型。

尽管C++当中对类型已经进行了十分详尽的定义,但还是存在一些与类型相关的标准未定义部分,主要包括以下方面:

  • char是否有符号

    不同的编译器有不同的定义,如果确定要制定char的类型,可以使用unsigned charsigned char

  • 整数在内存中的保存方式是大端法还是小端法

  • 每种类型的具体大小

    C++中只规定了每种基本类型的最小尺寸,而没有规定具体的尺寸,这种不确定性间接影响了取值范围,虽然提升了性能,但是降低了跨平台的可移植性质

    为了补充,在C++11中引入了固定尺寸的整数类型,比如int32_t等,具体的参考这里

字面值及其类型

字面值是在程序中直接表示为一个具体数值或者字符串的值。每一个字面值都有其对应的类型

  • 整数字面值:20(十进制),024(八进制),0x14(16进制)- int
  • 浮点数:1.3,1e8 - double
  • 字符字面值:‘c’,’\n’,’\x4d’ - char
  • 字符串字面值:“Hello” - char[6]

    注意末尾有’\0’,表示字符串的结束

  • 布尔字面值:true,false - bool
  • 指针字面值:nullptr - nullptr_t

以上所述的都是基本类型的字面值,我们可以为字面值引入前缀或者后缀以改变其类型,比如

  • 1.3(double)- 1.3f(float)
  • 2(int)- 2ULL(unsigned long long)

除此之外我们还可以使用自定义后缀来修改字面值,具体的可以参考这里

变量及其类型

C++中的变量本质上对应了一段存储空间,我们可以改变其中的内容。变量的类型在其首次声明(定义)时指定,比如

int x;

上面的代码定义了一个变量x,其类型为int

这里需要再次强调变量的声明与定义的区别,定义只能够出现一次,如果我们在其他的文件中想要使用这个变量,我们需要使用extern前缀来声明变量。

我们可以对变量进行初始化和赋值:

  • 初始化:在构造变量之初为其赋予初始值。初始化的方式主要有以下三种:
    1. 缺省初始化
      int x;
      

      如果变量声明在函数内部,缺省初始化的初始值为任意值。而对于全局变量、静态变量和线程相关的变量,缺省初始化的初始值为0。这么设计的主要原因是:对于一个函数内部的变量,由于他可能被调用多次,而每一次调用都为其赋予默认值是一件得不偿失的事情,严重影响了性能,所以设计为只为变量分配内存,而不对内存内的数据进行赋值。而对于全局变量来说,由于只需要赋予默认值一次,成本极低,而且保证了程序多次运行的一致性,所以会赋予一个默认的初始值。

    2. 直接/拷贝初始化
      int x = 10; // 拷贝初始化
      int x(10);	// 直接初始化
      int x{10};	// 直接初始化
      

      关于直接初始化和拷贝初始化的区别请参考这里
      关于使用大括号和小括号进行直接初始化的区别请参考这里

    3. 其他初始化:这里不讨论,有兴趣的可以自行研究。
  • 赋值:修改变量内的值

这里需要注意,使用extern的时候如果进行了非缺省的初始化,那么声明会自动升级为定义,导致多定义的错误

在对变量进行赋值时可能会涉及到隐式类型转换,比如以下两种:

  • bool 与整数之间的转换
  • 浮点数与整数之间的转换

注意在转换过程中可能会出现精度损失,比如从double -> int

除了发生在赋值和初始化过程中,隐式类型转换还会发生在其它情况下,比如:

  • if判断
  • 数值比较:最典型的是无符号整数和带符号整数的比较

    这种情况下根据标准会将带符号的整数转换成无符号的整数,所以在使用时一定要注意

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值