第二章 基本内置类型

    头一章我们已经大致了解了什么是计算机语言,也看了一个小小的C++的入门程序,那么为了更好地学习C++,就让我们从最基础的定义开始吧。

    众所周知,计算机语言除了C++外,还有其他的多种程序语言,比如C,Java,C#,Go,Object-C,甚至是php等脚本语言。这些语言看似各有不同,但实际上却有着如下一些极其相似的特征:

  •     内置数据类型
  •     变量
  •     表达式和语句
  •     控制结构(if else,while循环等)
  •     函数
  •     注释

    那么今天我们就从最基础的基本内置类型开始讲起吧。

一 计数方式

    学习前,首先我们需要搞清楚下面几个问题,即是什么是进制?以及什么又是bit和byte?

1. 二进制与十六进制

(1) 二进制

        所谓二进制,也就是逢二进位的计数方式。这又是什么意思呢?也许有些同学还不太清楚,那么就想想我们平常所使用的数字吧。

        平常我们习惯的的计数方式是十进制,也就是当个位数超过9的时候,就变成了10,即是,个位重新回归到了0,而十位上则增加了1,再加1的话,则个位继续增长,直到再次到了9,那么十位上再次加1,变成了20,依次类推,我们便可随着数字的增加,将位数由十位扩充到百位,千位,万位等等。

        而二进制也是如此,只不过,当它到2的时候,就需要进位了,数字上就变成了10,如果用十进制表示的话,它就是2,再继续增加,十进制的3则表示成了二进制的11,十进制的4则变成了二进制的100,十进制的5则是二进制的101等等。

        在C++语言中不直接使用二进制,而是使用八进制(以0开头),十进制(没有开头)和十六进制(以0x或0X开头)表示。

(2)十六进制

        十六进制的原理与二进制相同,但是由于它的数字超过了9,那么从10到15又该如何表示呢?很简单,使用字母a到f即可。而为了区分数字间进制的不同,C++中,十六进制则需要在数字前增加一个0x,这次用20来举例吧,0x14就是它的十六进制值。

2. bit与byte

    学习了二进制,再来说到bit和byte,也就轻而易举了。

(1)bit

        bit也就是二进制的位,计算机存储信息的最小单位。举个例子,比如十进制的4,也即是二进制的100,一共占用了3个bit。

(2)byte

        byte被称作字节,通常由8个bit组成,是计算机计算存储容量的一种计量单位。

二 基本内置类型

1. 算术类型

    C++将整数,浮点数,单个字符和布尔值合称为算术类型,其存储空间的大小依机器而定,这里的大小是指用来表示该类型的二进制位(二进制位称为bit)的数量。C++标准中规定了每个算术类型的最小存储空间,但是却并未限定编译器使用更大的空间。

    

Type

Meaning

Minimum size

bool

Boolean(布尔型)

NA

char

Character(字符型)

8 bits

wchar_t

Wide character(宽字符型)

16 bits

short

Short integer(短整型)

16 bits

int

Integer(整型)

16 bits

long

Long integer(长整型)

32 bits

float

Single-precision floating-point(单精度浮点型)

6 significant digits(有效数字)

double

double-precision floating-point(双精度浮点型)

10 significant digits(有效数字)

long double

Extended-precision floating-point(扩展精度浮点型)

10 significant digits(有效数字)

                                                                        图1


    如图1所示,即是内置算术类型所对应的最小存储空间,下图则是我在64位Mac OSX上使用g++编译器获得的存储空间。

Type

Meaning

Minimum size

bool

Boolean

8 bits

char

Character

8 bits

wchar_t

Wide character

32 bits

short

Short integer

16 bits

int

Integer

32 bits

long

Long integer

64 bits

float

Single-precision floating-point

32 bits

double

double-precision floating-point

64bits 

long double

Extended-precision floating-point

128bits

                                                                           图2

    此外还有long long超长整型,通过sizeof得到的是64bits二进制位。

    注意:

    1. 这些内部关键字都为小写;

    2. 在64位Mac OSX苹果系统上测试数据,如有不同,请自行用sizeof在其他系统上查看;

    以后将不再专门提起。

(1)整型

    所有整型可分为带符号(signed)与无符号(unsigned)两种类型,其中带符号类型可以表示正数,也可以表示负数(包括0),而无符号型则只能表示大于或等于0的数,如果未写unsigned,则默认都是带符号类型,比如unsigned int,表示的是无符号整型。

    那么带符号数值的正负又是如何区分的呢?如下图3所示:


signed:

                        图3

     带符号数在内存中二进制的首位就是符号位,0代表正数,1代表负数,其中二进制位个数有可能随编译器和机器的不同而不同,此文中的位数个数为目前64位机较为普遍的存储方式。

    A. 短整型

        定义为short,内存中所需的二进制位为16位(注意编译器与机器的不同),即2个字节,带符号短整型可表达的数字范围是从-32768到32767,无符号的范围则是0到65535。

    下面来看看这是如何计算出来的吧。首先说带符号短整型,16位二进制,最高位为符号位,则可表示为数字的就只剩下了15位,意思就是说,如果最高位为0,即正数,则数值的最大值就是15位全部为1。

    因为是二进制,15位,每位只能为0或者1,根据排列组合的计算原理,最大值应该为:2的15次方,再减1(215 - 1)。同理,无符号数的最大值为:2的16次方,减1(216 - 1)。

    也许有些同学会不太明白为什么要这么计算,那我们就来简单地说一下吧。

    比如我们不求15位,我们以简单的3位来举例,三个bit位,000,001,010,011,100,101,110,111一共有八种排列的方式,其对应的十进制数分别是0,1,2,3,4,5,6,7,由此,我们可以看出每种排列方式都是独一无二的,那么我们只要减去全为0的这一种排列方式,得到的就是3位二进制的最大值了。

    这时,也许有同学会问了,三位还好办,如果位数多了,难道我们也要这么一个个排出来吗?当然不可能了。上面的方法只不过是为了让你明白一个简单的道理罢了,什么道理呢?

    就是我们想要求n位二进制的最大值,只需要求得这n位所有的排列组合的个数,再减去1就是我们所需的结果了。那么又要怎么去求n位的所有的排列组合的个数呢?

    很简单,再拿三个bit位举例,首先只看一位,一共就0和1两种方式,这时,再加上一位,而这一位也只能是0和1两种,而不论是0还是1,头一位都只有两种方式,不过,因为第二位的不同,这时的组合方式就变成了2乘以2,一共4种方式,同理,再加上一位,这一位还是只有0和1两种方式,不过前面两位则不管是0还是1都有4种不同的方式,结合这第三位,那么总共就有4乘以2,一共8种方式了。

    现在,大家应该都看明白了吧,总结起来说就是,要得到总的排列组合个数,就是每一位的方式的个数相乘,所得到的乘积就是我们所需要的结果了,在这里,因为方式都是只有0和1两种,也就是说,n位的排列组合个数等于2的n次方。

    言归正传,短整型存储的位数是16位,如果是带符号数,最高位作为标志位,则可能出现正0与负0两种,而负0在这里就是人为地规定为最小值-32768,想要知道详细信息请看下章关于原码,反码和补码的相关内容。

    B. 整型

      原理同上,就不再多说,定义为int,内存中的二进制位为32位,4个字节,带符号短整型可表达的数字范围是从-2147483648到2147483647,无符号的范围则是0到4294967295。

    C. 长整型

       定义为long,内存中的二进制位为64位,8个字节,带符号短整型可表达的数字范围是从-92233720368547758089223372036854775807,无符号的范围则是0到18446744073709551615

    D. 超长整型

        定义为long long,内存中的二进制位为64位,8个字节,范围同长整型

(2)字符型

    A. 字符型

        定义为char,内存中二进制位为8位,1个字节,这个字符型基本所有的机器都是如此存储的。也分为带符号和无符号两种。
      B. 宽字符型
        定义为wchar_t,内存中二进制位32位,4字节。

(3)布尔型

      定义为bool,内存中二进制位为8位,1个字节,值为true和false,不过,也可以用其他算术类型的非0表示true,0表示false。

(4)浮点型

     浮点型同整型在内存中的存储方式有所不同,为了更完整地记录数据信息,它采用了二进制的科学计数法来存储数据。那什么是二进制的科学计数法呢?

    为了让大家更好地理解,我们就先用十进制的科学计数法来解释一下吧。

    所谓科学计数法,打个比方,735.2,用科学计数法来表示就是7.352 * 10n,即,将一个数字记录成某个个位数大于0的数字乘以10的n次方的值,这个值与原数字是相等的,这种记数的方法就叫科学计数法。

    而二进制的科学计数法,顾名思义,就是将一个数字记录成某个个位数大于0的二进制数字乘以2的n次方的值,这个值也必须与原数字相等,用表达式来表示就是:1.xxx * 2n

    为了方便大家理解,用75.25来打个比方,转换成二进制为1001011.01,用二进制的科学计数法表示出来就是1.00101101 * 26

    这是如何计算出来的呢?

    首先将75.25分成整数部分和小数部分,两部分分开计算成二进制,先来看看整数部分,要想得到二进制,只需要将75除以2,得到结果为37余1,之后再用37除以2,得到结果18余1,以此类推,直到结果为0,最后将所有的余数按从后往前取,得到的二进制数就是结果,见下图所示:


                图4

    75的二进制就是1001011。

    再来提小数部分,0.25,其提取方式与整数部分正好相反,使用乘法,取结果的整数值,最终结果的取值顺序按从前往后,如下:

    0.25 * 2 = 0.5    取整数部分0

    0.5 * 2 = 1         取整数部分1

    小数部分的最终结果就是01,加上小数点就是0.01。

    好了,现在小数部分和整数部分都已经有了,整合起来就是1001011.01,表达成二进制科学计数法即是:1.00101101 * 26。也许有些同学还想知道为什么会这么计算呢?其实想想短整型里面提到的原理,逆转一下思维,就能够明白其中的道理了。

    说到这里,大家应该都已经明白了二进制的科学计数法,下面就来继续说说浮点型数据在内存中的存储方式吧。

    从下图5我们可以看出,浮点型在内存中主要分为三个部分,其中符号位很好理解,而指数部分,看看上面的1.00101101 * 26,这个6就是指数,它将被存储在指数位,而0.00101101将被存储于尾数部分。


                                图5

  •     符号位
        占1bit,0表示正数,1表示负数。          
  •     指数位   

        用于存储二进制科学计数法的指数值,因为指数也可以有正负,因此指数位的最高位还是不计算在范围内,但是它的方式又与符号位不同,它的值是从0到最大值,但是,实际表达的值却是将它均分成正负。

  •     尾数部分

        用于存储二进制科学计数法当中的实际数据的小数部分,因为方式都是1.xxx,所有那个小数点前面的1就没了记录的必要。另外,浮点型都没有带符号与无符号的区别。

    A. 单精度浮点型

        定义为float,内存中占32位,4个字节,数据范围为-2128~2128,也即是-3.40E38~3.40E38,其存储方式遵循IEEE754 R32.24标准,其中最高位是符号位,0为正,1为负,指数位占8个bit,尾数部分占23个bit,如下图6:


                                图6

        且不提符号位,在这里说说指数位的存储方式,因为指数也分正负,在这里二进制是从00000000到11111111,如果按照以往的最高位作为符号位的存储,那么就会有正0与负0的问题,为了更好地将数据按照顺序记录,也就是不会在中途来解决正0和负0的问题,这里就采用了一种移位存储的方式。

        提到移位存储,首先我们需要一个基数,这个基数的确定方法就是将最高位设定为0,其余位设定为1,在这里,8位指数的基数就是01111111(127),然后将所需要存储的数据加上这个基数,那么就可以按照顺序唯一表示从-128到127的范围,而不需要再单独处理正0和负0的问题了。

    详细看下图7:



                                图7

        以上便是指数部分的存储了,至于尾数部分,就更简单了,直接将上面提到的尾数放入即可,不足补零,下面来看一个完整的例子吧。

        还是以75.25(1.00101101 * 26)为例,存储的数据中,符号位为0,指数位6,存储为6 + 127 = 133,即是10000101,尾数部分00101101,不足23位,其后补零,如图8:


                                                                    图8

        另外,还需要注意一点,尾数部分也决定了精度和有效数字,首先说说精度,比如75.2,其小数部分计算出来就是001100110011......,这数字与实际的十进制所说的数字有部分出入,这就是所说的精度问题。

        而关于有效数字,这尾数部分最大值可为223 -1 = 8388607,一共7位数字,这就是前面提到的有效数字。

    B. 双精度浮点型

        定义为double,内存中占64位,8个字节,数据范围为-21024~21024,也即是-1.79E308~1.79E308,遵循IEEE754 R64.53标准,最高位是符号位,0为正,1为负,指数位占11个bit,尾数部分占52个bit,如下图9:

                                    图9

        其设计原理与单精度浮点型相同,不同的是存储的长度不同,这导致了数据范围的不同,还有基数也变为了0111111111(1023),有效数字增大到252 -1 = 4503599627370495,一共16位数字。

    C. 扩展精度浮点型

        定义为long double,内存中占64位,8个字节,同双精度浮点型。

2. void空类型

    void类型没有对应的值,是一种特殊的类型,通常用做无返回值函数,以及通用的指针使用,在此不做详谈,等以后接触到的时候,再提及。

猜你喜欢

转载自blog.csdn.net/rsp19801226/article/details/80653885