企业网站建设最新技术,wordpress小型论坛主题,天津网站建设哪家做得好,担路网口碑做网站好吗Hi~#xff01;这里是奋斗的小羊#xff0c;很荣幸各位能阅读我的文章#xff0c;诚请评论指点#xff0c;欢迎欢迎~~      #x1f4a5;个人主页#xff1a;小羊在奋斗 #x1f4a5;所属专栏#xff1a;C语言    本系列文章为个人学习笔记#xff0c;在这里撰写成文一…         Hi~这里是奋斗的小羊很荣幸各位能阅读我的文章诚请评论指点欢迎欢迎~~                                                      个人主页小羊在奋斗                                                 所属专栏C语言    本系列文章为个人学习笔记在这里撰写成文一为巩固知识二为一些学友们展示一下我的学习过程及理解。文笔、排版拙劣望见谅。  1、大小端字节序和字节序判断 2、浮点数在内存中的存储 2.1浮点数存的过程 2.2浮点数取的过程 
1、大小端字节序和字节序判断 在 C语言操作符1 中我们介绍了整数在内存中的存储但是我们只介绍了整数的存储形式并没有介绍整数是如何存储的那本节我们就来探讨一下整数在内存中究竟是怎么存储的。 当我们想把0x11223344这个数存到一个整型变量a中时因为整型数据的大小是4个字节以字节为单位存储那么11占一个字节22占一个字节33占一个字节44占一个字节假设从低地址向高地址存储那先存11还是先存44就是一个问题。其实超过一个字节的数据在内存中存储的时候就有存储顺序的问题按照不同的存储顺序我们分为大端字节序存储和小端字节序存储。 也就是说大端字节序存储是地址由低到高依次存高位小端字节序存储是地址由低到高依次存低位。 我们之前可能会疑惑VS中整数在内存中为什么是反着存的那这里就给了我们解释VS所在的当前计算机系统使用的是小端字节序存储而大多数计算机架构使用的都是小端字节序存储。 如果我们想知道当前的机器使用的是哪种存储方式可以写一个简单的判断小程序来实现。当我们在一个整型变量中存一个整数1时如果当前机器是大端字节序存储那么它存的就是         00 00 00 01如果当前机器是小端字节序存储那么它存的就是 01 00 00 00。既然如此我们只需要将这个整型变量最小字节中的数据拿出来看这个最小字节单元中存的数是0还是1如果是0就是大端字节序存储反之则为小端字节序存储。 了解了大小端存储我们来做一些练习加深理解。 练习1  上面代码的输出结果是什么呢其实我们在C语言操作符2中的表达式求值部分已经学习过我们来分析一下 我们想将整数-1存入一个字符型变量a中整型和字符型不兼容通过C语言操作符2的学习我们知道要发生截断所以只将-1的补码的后8位存到a中我们又用%d打印有符号整型打印字符型变量a那%d就认为它打印的数是整型a不是整型所以要发生整型提升a是charsigned char类型整型提升高位补符号位补完后还是32个1取反加一得原码又变为了-1最终结果就打印出了-1因为在VS中char和signed char是一样的所以打印b也就同样的道理。 而我们将整数-1存入一个无符号字符型变量c中截断只存入-1的补码的后8位用%d打印需要整型提升而c是无符号字符型整型提升高位补0补完后用%d打印时%d看它就是一个比较大的正数原反补相同00000000000000000000000011111111就是255。 练习2  将整数-128补码11111111111111111111111110000000存入signedchar类型a中截断后a中存的是10000000用%u打印无符号整数打印需要整型提升a为signed char所以高位补符号位补完就是11111111111111111111111110000000目前还是补码但是在%u眼中无符号整形原反补相同所以%u再以原码打印出来就是4294967168。 将a改为128结果还是一样的因为它们截断的结果是一样的。 至于为什么对a存-128还是128结果是一样的这里再做一个解释 我们很早就知道signedchar类型的取值范围是-128~127 但是为什么是这个范围并没有解释。char类型占一个字节也就是8个比特位最高位当做符号位来看待就剩下了7位存0、1值。 在C语言操作符2中我们还画了这样一个图并做了相应解释。 1271在数学上是128但在char类型中就是-128因为char类型最大的正数就是127所以给char类型存128和-128是一样的。其他的类型都是这样的道理。 练习3  创建一个字符数组大小1000向数组中存入-1、-2、-3..然后strlen求字符数组a的长度。我们知道strlen是求字符串的长度统计的是\0之前的字符个数那看来意思就是让我们找字符‘\0’了又因为a是字符数组所以-1、-2、..、-127、-128、127、126、...、2、1、00在字符眼中就是\0所以求的是-1~0的长度是255。 练习4  unsigned char的范围是0~255所以上面的代码给我们的感觉就是打印255个hello world但事实真是如此吗当我们运行起来就会发现程序陷入了死循环。这是因为当i加到256时虽然此时不满足循环了但是这时候的256只是数学上的256而在unsigned char眼中2551就变成了0所以循环继续。 上面这个代码也是如此当i为0时0-1就变成了2^32-1因为在unsigned int的世界里没有负数所以程序陷入了死循环。 练习5 创建一个整型数组大小4a取出整个数组的地址再1跳过整个数组指向数组末尾此时指针地址的类型是int (*) [4]再强转为 int * 类型的指针赋给ptr1ptr1[-1] *(ptr -1) 就是int *类型的指针-1向后推4个字节指向数组最后一个元素4再解引用用%x打印16进制打印出来就是4。 数组名a表示数组首元素的地址强转为int类型的整数再1再强转为int *类型的指针最终的结果就是数组首元素的地址1整数1注意ptr2是一个整型类型的指针所以它访问的是4个字节的地址。 我们又知道小端字节序是反着存的所以ptr2指向的数值就是02 00 00 00打印出来就是2000000。 如果我们想把代表16进制的0x也打印出来可以在%的后面加上#。 2、浮点数在内存中的存储 2.1浮点数存的过程 浮点数和整数在内存中的存储有什么区别吗 如果用我们学到的整数存储的方法来解读上面的代码打印出来的结果应该就是9、9.000000、9、9.000000。 但结果并不是这样通过观察我们发现只有当n是整数9时用%d打印的结果和当n是浮点数9.0时用%f打印的结果是我们预料中的所以可以肯定的是整数和浮点数在内存中的存储是不一样的。 那浮点数在内存中是怎么存的呢根据 IEEE 754规定任意一个二进制浮点数V可以表示为这样的形式V(-1)^S*M*2^E。(-1)^S表示符号位当S0V为正数当S1V为负数。M表示有效数字M是大于等于1小于2的。2^E表示指数位。 比如十进制的5.5写成二进制就是101.1转化的方法是按位权来转化小数点前面的位权是2的1次方、2的2次方、2的3次方....小数点后面的位权是2的-1次方、2的-2次方、2的-3次方......。十进制的5.5二进制表示101.1用科学计数法表示就是1.011*2^2又因为5.5是正数所以用IEEE 754标准表示就是(-1)^0*1.011*2^2。其中的S0M1.011E2。 任何一个浮点数都可以用S、M、E这三个值来表示所以浮点数的存储存储的就是S、M、E 相关的值。 IEEE 754规定 对于32位的浮点数float最高的1位存储符号位S接着的8位存储指数E剩下的23位存储有效数字M。 对于64位的浮点数double最高的1位存储符号位S接着的11位存储指数E剩下的52位存储有效数字M。 IEEE 754对有效数字M和指数E还有一些特别规定。  前面说过1M2所以M总是1.xxxxxIEEE 754规定在计算机内部保存M时默认这个数的第一位是1因此1可以舍去只保存小数点后面的xxxxx读取的时候再把第一位的1加上就行。这样做的目的是节省1位有效数字使存储的精度更高。  E作为一个无符号整数如果E为8位它的取值范围是0~255如果E为11位它的取值范围是0~2047。但是在科学计数法中指数有可能是负数所以 IEEE 754规定存入内部的E的真实值必须再加上一个中间数对8位的E这个中间数是127对11位的E这个数是1023。比如2^10的E是10保存成32位的浮点数时必须保存成137即10001001。我们也不用担心加上这个中间数后E的值还不能为正数因为当E非常小时已经无限接近于0了而float和double也是有精度限度的。 比如float类型的5.5在内存中的存储就是 本计算机系统采用的是小端字节序存储。  2.2浮点数取的过程 指数E从内存中取出的过程可分为三种情况 E不全为0或不全为1常规情况 指数E的计算值减去127或1023得到真实值再将有效数字M前加上第一位的1。 E全为0罕见 这时浮点数的指数E等于1-127或1-1023即为真实值有效数字M不再加上第一位的1而是还原为0.xxxxx的小数。这样做是为了表示-0以及无限接近于0的极小的数字。 E全为1罕见 这时E的真实值为255-127128这又是一个极大的数大到我们无法想象所以就不去讨论它了。 了解清楚了浮点数在内存中的存取后我们再来分析一下前面的那个代码。 创建一个整型变量n赋值为9用%d打印时就按常规打印出整数9。我们再取出n的地址将其强转为float *类型的指针再赋给pfloat再解引用pfloat用%f打印9在内存中的补码是 
00000000000000000000000000001001而pfloat是float *类型的指针所以pfloat就认为它指向的数是一个浮点数就会按浮点数存取的规则来读取在pfloat眼中整数9的补码是这个样子 S0E为全0那这个值就是一个极小的正数无限接近于0而float只能打印小数点后6位所以打印的结果应该就是0.000000。 而将9.0存到float *类型的地址中时9.0用二进制表示为1001.0根据 IEEE 754 规定S0M1.001E3那在内存中的存储就应该是下面这个样子的 用%d打印时%d就认为这是一个很大的正数 原反补相同。而用%f打印就是正常的9.000000。 本节内容并不需要我们死记硬背只需要知道整数和浮点数在底层是怎么存取的又有什么差异当某天我们错用格式符打印不同类型的值时我们要知道是怎么回事要会分析为什么会输出这个值这个值是随机的还是有它的道理的就行。 只要我们遵守规则有符号整数就用%d打印无符号整数就用%u打印float类型就用%f打印double类型就用%lf打印size_t类型就用%zd打印……就行。 如果觉得我的文章还不错请点赞、收藏  关注支持一下我会持续更新更好的文章。