您的位置:首页 > 编程语言 > C语言/C++

4、C语言深度学习笔记--基础知识

2018-03-24 16:05 423 查看
一、整数在计算机中的表示

1、现在⼏乎所有计算机都采⽤⼆进制数(Binary)编码⽅式,所以我们⽇常所⽤到的整数如果要⽤计算机来表⽰的话,需要表⽰成⼆进制的⽅式。
2、在计算机术语中,把⼆进制数中的某⼀位数又称为⼀个⽐特(bit)。⽐特这个单位对于计算机⽽⾔,在度量上是最⼩的单位。除了⽐特之外,还有字节(byte)这个术语。⼀个字节由8个⽐特构成。在某些单⽚机架构下还引⼊了半字节(nybble或nibble)这个概念,表⽰4个⽐特。然后,还有字(word)这个术语。字在不同计算机架构下表⽰的含义不同。在x86架构下,⼀个字为2个字节;⽽在ARM等众多32位RISC体系结构下,⼀个字表⽰为4个字节。随着计算机带宽的提升,能被处理器⼀次处理的数据宽度也不断提升,因此出现了双字(double word)、四字(quad word)、⼋字(octa word)等概念。双字的宽度为2个字,四字宽度为4个字,所以它们在不同处理器体系结构下所占⽤的字节个数也会不同。
3、整数在内存中的存放形式
(1)如果定义了一个整型变量 i:
//
int i;
i = 10;
//(2)int型占2个字节,最终数值是以补码表示的,具体如下



a、正数的补码和原码相同;
b、负数的补码:将该数的绝对值的二进制形式按位取反(求得反码)再加 1。

二、浮点数在计算机中的表示
1、当前主流处理器⼀般都能⽀持32位的单精度浮点数与64位的双精度浮点数的表⽰和计算,并且能遵循IEEE754-1985⼯业标准。现在此标准最新的版本是2008,其中增加了对16位半精度浮点数以及128位四精度浮点数的描述。C语⾔标准引⼊了⼀个浮点模型,可⽤来表达任意精度的浮点数,尽管当前主流C语⾔编译器尚未很好地⽀持半精度浮点数与四精度浮点数的表⽰和计算。
2、⼀个浮点数包含了整数部分和尾数(即⼩数)部分。整数部分的表⽰与我们之前所讨论过的⼀样,第n位就表⽰2^n,n从0开始计。⽽尾数部分则是第m位表⽰2^m ,m从1开始计。对于⼀个0101.1010的⼆进制浮点数对应⼗进制数的计算

如下图所⽰



图中,整 i 位即表⽰第 i 位整数;尾 i 位即表⽰第 i 位尾数。其中,第3位整数为最⾼位整数;第4位尾数表⽰最低位尾数。对⼆进制浮点数的表⽰有了概念之后,我们就可以看IEEE754-1985标准中对规格化浮点数的描述了。IEEE754-1985对32位单精度与64位双精度两种精度的浮点数进⾏描述。32位单精度浮点可表⽰的数值范围在±1.18×10^38 到±3.4×10^38 ,⼤约含有7位⼗进制有效数;64位双精度浮点可表⽰的数值范围在±2.23×10^308 到±1.80×10^308 ,⼤约含有15位⼗进制有效数。我们看到IEEE定义的浮点数的绝对值范围可以是⼀个远⼤于1的数,也可以是⼀个⼤于零但远⼩于1的数,即它的⼩数精度是可浮动的,所以称之为浮点数。如果说是定点数的话,它也可表⽰⼀个⼩数,但是其整数位数与⼩数位数的精度都是固定的。⽐如⼀个16.16的定点数表⽰整数部分采⽤16个⽐特,尾数部分也采⽤16个⽐特。⽽对于⼀个32位浮点数来说,既能使⽤16.16的格式,也能使⽤30.2的格式(即30个⽐特表⽰整数,2个⽐特表⽰尾数)或其他各种形式。⽽IEEE754-1985对规格化单精度浮点数的格式如下定义:

a、1位符号位,⼀般是最⾼位(31位),表⽰正负号。0表⽰正数,1表⽰负数。
b、8位指数位,又称阶码,位于23到30位。

c、23位尾数,位于0到22位。
举例:⼀个⼗进制⼩数5.625
a、5.625是⼀个正数,所以符号位为0,即第31位为0。
b、我们将5.625依照上图那样写成⼀般⼩数的表⽰法——0101.101。
c、我们将此⼆进制浮点数⽤科学计数法来表⽰,使得⼆进制整数位为最⾼位的1。这⾥最⾼位为1的⽐特是从左往右数是第⼆个⽐特,所以将⼩数点就放到该⽐特的后⾯,得到1.01101×2^2 。⼆进制数的科学记数法,底数的值显然就是2。
d、此时,我们能看到尾数部分是⼩数点后⾯的那串⼆进制数,即01101,⽽指数为2。现在我们来求阶码。阶码⽤的是中经指数偏差(exponent bias)处理后的指数,即⽤上述得到的指数加上偏差值所求得的和。IEEE754在单精度浮点中规定,偏差值为127。所以本例中,阶码部分为2+127=129,⽤⼆进制数表⽰就是10000001。
e、尾数部分从⼤到⼩照抄,低位的⽤0填充即可,所以这⾥的尾数部分⼆进制数为:01101000000000000000000。
f、将整个处理完的⼆进制数串起来获得:0(符号位)10000001(阶码)01101000000000000000000(尾数),⽤⼗六进制数表达就是:40B40000。⼗进制⼩数转64位双精度浮点数的⽅法与上述雷同,只不过阶码⽤11位⽐特来表⽰,尾数则⽤52位⽐特表⽰,⽽偏差值则规定为1023。

三、地址与字节对齐
1、由于C语⾔是⼀门接近底层硬件的编程语⾔,它能直接对存储器地址进⾏访问(当前⼤部分处理器在操作系统的应⽤层所访问到的是逻辑地址,⽽部分嵌⼊式系统由于不含带存储器管理单元,因此可直接访问物理地址)。在计算机中,所谓“地址”就是⽤来标识存储单元的⼀个编号,就好⽐我们住房的门牌号。没有门牌号,快递就没法发货;如果门牌号记错了,那么快递就会把货物送错地⽅。计算机中的地址也是⼀样,我们为了要访问存储器中特定单元的⼀个数据,那么我们⾸先要获悉该数据所在的地址,然后我们通过这个地址来访问它。访问存储器,我们也简称为“访存”(Memory Access)。访问地址,我们也简称为“寻址”(Addressing)。⼀般计算机架构中都会有地址总线和数据总线。CPU先通过地址总线发送寻址信号,以指定所要访问存储器单元的地址。然后再通过数据总线向该地址读写数据,这样就完成了⼀次访存操作。这好⽐于快递送货,我们先打电话告诉快递通信地址,然后快递员把货送到该地址(写数据),或者去该地址拿货(读数据)送到别家。⼀般对于32位系统来说,处理器⼀次可访问1个(8⽐特)字节、2个字节或4个字节。当访问单个字节时,对CPU不做对齐限制;⽽当访问多个字节时,⽐如要访问N个字节,由于计算机总线设计等诸多因素,要求CPU所访问的起始地址满⾜N个字节的倍数来访问存储器。如果在访问存储器时没有按照特定要求做字节对齐,那么可能会引发访存性能问题,甚⾄直接导致寻址错误⽽引发异常(引发异常后通常会导致当前应⽤意外退出,在嵌⼊式系统中可能就直接死机或复位)。下⾯我们给出⼀张图来描述,看看⼀般对32位系统⽽⾔如何正确地做到访存字节对齐。下图展⽰了如何正确对齐访问1个字节、2个字节和4个字节的情况。图中画出了6个存储单元内容,地址低16位从0x1000到0x1005,每个存储单元为1个字节。对于仅访问1个字节的情况,图2-8所有地址都能直接访问并满⾜字节对齐的情况。对于⼀次访问2个字节的情况,要满⾜对齐要求,只能访问0x1000、0x1002、0x1004等必须要能被2整除的地址。对于⼀次访问4字节的情况,要满⾜对齐要求,则只能访问0x1000、0x1004等必须要能被4整除的地址。



然⽽,并不是说要访问多少字节,就必须要保证访问能被多少整除的地址才能满⾜对齐要求。如果⼀次访问8字节,对于32位系统⽽⾔,通过32位通⽤⽬的寄存器来读写存储器的话,某些CPU会⾃动将8字节的访存分为两次进⾏操作,每次为4字节,因此只要保证4字节对齐就能满⾜对齐要求。这些都根据特定的处理器来做具体处理。像x86、ARM等处理器,当访存不满⾜对齐要求时并不会引发总线异常,但是访问性能会降低很多。因为原本可⼀次通信的数据传输可能需要拆分为多次,并且前后还要保证数据的⼀致性,所以还可能会有锁步之类的操作。⽽像Blackfin DSP则会直接引发总线异常,导致整个系统的崩溃(如果不对此异常做处理的话)。另外,像ARMv5或更低版本的处理器,在对⾮对齐的存储器地址进⾏访问时,CPU会先⾃动向下定位到对齐地址,然后通过向右循环移位的⽅式处理数据,这就使得传输数据并不是原本想⼀次传输的数据内容,也就是说写⼊的或读出的数据是失真的。⽐如,根据图所⽰内容,如果我们要对⼀款ARM7EJ-S处理器(ARMv5TEJ架构)从地址0x1002读4字节内容,那么实际获取到的数据为0x02010403;⽽在x86架构或ARMv7架构的处理器下,则能获得0x06050403。

四、字符编码
1、现在⽤得更多的UTF-8编码标准。UTF-8属于变长的编码⽅式,它最少可⽤1个字节表⽰1个字符,最多⽤4个字节表⽰1个字
符,判别依据就是看第1个字节的最⾼位有多少个1。如果第1个字节的最⾼位是0,那么该字符⽤1个字节表⽰;最⾼3位是110,那么⽤2个字节表⽰;最⾼4位是1110,那么⽤3个字节表⽰;最⾼位是11110,那么该字符由4个字节来表⽰。所以UTF-8现在⼤量⽤于⽹络通信的字符编码格式,包括⼤多数⽹页⽤的默认字符编码也都是UTF-8编码。尽管UTF-8更为灵活,⽽且也与ASCII码完全兼容,但不利于程序解析。所以现在很多编程语⾔的编译器以及运⾏时库⽤得更多的是UTF-16编码来处理源代码解析以及各类⽂本解析,它与之前的UCS-2编码完全兼容,但也是变长编码⽅式,可⽤双字节或四字节来表⽰⼀个字符。

五、⼤端与⼩端

1、现代计算机系统中含有两种存放数据的字节序:⼤端(Big-endian)和⼩端(Little-endian)。所谓⼤端字节序是指在读写⼀个⼤于1个字节的数据时,其数据的最⾼字节存放在起始地址单元处,数据的最低字节存放在最⾼地址单元处。所谓⼩端字节序是指在读写⼀个⼤于1个字节的数据时,其数据的最低字节存放在起始地址单元处,⽽数据的最⾼字节存放在最⾼地址单元处。⽐如,我们要在地址0x00001000处存放⼀个0x04030201的32位整数,其⼤端、⼩端存放情况如图所⽰。



当前,通⽤桌⾯处理器以及智能移动设备的处理器⼀般都⽤⼩端字节序。通信设备中⽤⼤端字节序⽐较普遍。
致谢1、《C语言编程魔法书》作者 陈轶
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: