C语言数据在内存中的存储:整型与浮点型的秘密
C语言数据在内存中的存储整型与浮点型的秘密数据在内存中以二进制形式存储但整型和浮点型的存储方式截然不同。本文将深入讲解整型的原码、反码、补码揭示大小端字节序的本质并通过大量练习帮助理解截断与提升最后解析浮点数遵循的IEEE754标准带你彻底搞懂数据在内存中的真实面貌。目录一、整数在内存中的存储二、大小端字节序和字节序判断三、浮点数在内存中的存储一、整数在内存中的存储整数的二进制表示有原码、反码、补码三种形式正数原码、反码、补码相同。负数原码符号位为1数值位为绝对值的二进制反码符号位不变其余取反补码为反码1。计算机中整数一律使用补码存储。原因符号位和数值域统一处理。加减法统一为加法运算CPU只有加法器。补码与原码转换过程相同无需额外硬件。示例int a 0x11223344;在内存中调试发现字节顺序是倒着存储的如44 33 22 11这就涉及大小端问题。二、大小端字节序和字节序判断2.1 什么是大小端对于超过一个字节的数据存在存储顺序问题大端模式数据的低字节保存在高地址高字节保存在低地址。小端模式数据的低字节保存在低地址高字节保存在高地址。图示0x11223344 在小端中存储为 44 33 22 11在大端中为 11 22 33 442.2 为什么有大小端因为寄存器宽度大于一个字节时需要安排多字节存储顺序。不同架构选择不同X86为小端模式KEIL C51为大端ARM可配置。2.3 经典练习练习1判断当前机器字节序百度笔试题intcheck_sys(){inti1;return*(char*)i;// 取第一个字节1为小端0为大端}练习2char类型截断与提升chara-1;// 补码 11111111signedcharb-1;// 同aunsignedcharc-1;// 11111111作为无符号值为255printf(%d,%d,%d,a,b,c);// -1,-1,255练习3char范围与%u打印chara-128;// 补码 10000000printf(%u\n,a);// 整型提升为 11111111111111111111111110000000 → 4294967168charb128;// 128超出char范围-128~127存为 -128printf(%u\n,b);// 同样输出 4294967168练习4字符数组与strlenchara[1000];for(i0;i1000;i)a[i]-1-i;printf(%d,strlen(a));// 遇到第一个0停止数组从-1,-2,...到-128,127,126...0共255个非0练习5无符号循环陷阱unsignedchari0;for(i0;i255;i)// 无符号char永远≤255死循环printf(hello\n);unsignedinti;for(i9;i0;i--)// i0永远为真死循环printf(%u\n,i);注意无符号整数永远非负循环条件需谨慎。练习6指针与字节偏移inta[4]{1,2,3,4};int*ptr1(int*)(a1);int*ptr2(int*)((int)a1);printf(%x,%x,ptr1[-1],*ptr2);a1跳过整个数组ptr1[-1]指向最后一个元素 →4(int)a 1将数组首地址转为整数后1字节再转为int*指向从第二个字节开始的内存在小端环境下取出的整数为0x02000000即2000000输出小端机器上为2000000实际依赖环境。三、浮点数在内存中的存储3.1 一个令人困惑的例子intn9;float*pFloat(float*)n;printf(%d\n,n);// 9printf(%f\n,*pFloat);// 0.000000*pFloat9.0;printf(%d\n,n);// 1091567616printf(%f\n,*pFloat);// 9.000000为什么同样的内存整型和浮点型解读结果完全不同因为浮点数遵循IEEE754标准。3.2 IEEE754浮点数表示任意二进制浮点数V可表示为[V (-1)^S \times M \times 2^E]S符号位0正1负。M有效数字范围1 ≤ M 2。E指数。对于32位float1位S8位E23位M。对于64位double1位S11位E52位M。特殊规则M的存储因为1 ≤ M 2默认第一位总是1可以舍去只保存小数部分读取时再补回。这样多了一位精度。E的存储E为无符号整数但实际可正可负所以存时加上中间值float加127double加1023。E全0表示非常接近0的数字此时M不再加1还原为0.xxxxx指数为1-127或1-1023。E全1若M全0表示±无穷大。3.3 题目解析为什么9变成浮点数是0.0000009的二进制补码0000 0000 0000 0000 0000 0000 0000 1001按float拆解S0E00000000全0M000…1001。由于E全0浮点数为(-1)^0 × 0.000...1001 × 2^(-126)极小的正数 → 0.000000。为什么9.0变成整数是10915676169.0的二进制1001.0→1.001 × 2^3S0E3127130二进制10000010M001后面补20个0。二进制序列0 10000010 00100000000000000000000按整数解析补码即为1091567616。总结整型数据在内存中以补码存储大小端影响多字节顺序char类型参与运算需注意截断与整型提升无符号循环易死循环。浮点数遵循IEEE754标准其存储与整型完全不同解读方式取决于类型。掌握这些知识能帮助我们理解指针类型转换、数据溢出、字节序等底层行为写出更健壮的代码。