long double在内存中的存储方式
最近在学习浮点数相关的知识,float和double已经能完全理解了,但是long double这个类型,感觉存储的方式很奇怪啊以最简单的浮点数为例,3.0
按浮点数的存储方式,3.0应该变成1.5 * 2 ^ 1,也就是二进制1.1 * 2 ^ 1,在内存中的存储,符号位是0,指数位最高位为1,后面为0,底数位去掉小数点前的1,最高位1,后面为0
实测,float在内存中是0x40400000,double在内存中是0x40800000 00000000,两者都符合上面的分析
但到了long double,情况完全不一样了。网上查到,float为32位,double为64位,long double为96位,也就是float占4字节,double8字节,long double应该12字节,实测前两者没问题
long double在不同的架构下结果完全不同
在32位x86 centos 7,gcc 4.8.5中,long double长度为12字节,也就是96位,没问题,但到了arm中,同样是centos 7,同样是32位,同样是gcc4.8.5,long double却只有8字节,存储方式跟double完全一样。mips debian 32位中,gcc 8.3,long double跟double也完全一样
到了64位系统中,我分别测试了linux mint 20 gcc 4.8.4,linux mint 20 gcc 9.3和centos 8 gcc 8.3,这三个结果相同,长度都为16字节。
以上是内存占用。然后再说一下具体的存储方式
几个32位系统,除了centos 7 gcc 4.8.5,其他几个都跟double完全一样,就不再讨论了
centos 7 gcc 4.8.5虽然比64位系统中long double小了4字节,但是低位的12字节存储方式是完全一样的,64位系统中高4字节全为0,所以这几个可以一起讨论
按前面说的存储方式,long double的值3.0,理论上应该是最高位符号位为0,指数最高位为1,后面为0,底数位最高位1,后面为0,也就是在内存中应该存储为0x40008000 00000000 00000000
但是,实测发现内存中存储的是这个值:0x00004000 c0000000 00000000
又测试发现-3在内存中是0x0000c000 c0000000 00000000
也就是说,符号位不是96位中的最高位,高16位始终为0,实际占用的只有80位
然后,底数不是刚才分析的最高位1,后面为0,而是最高2位为1,后面为0,底数没有删掉小数点左边的1
贴上我测试用的代码:
程序代码:
#include <stdio.h> #include <string.h> int main() { union { int i[1]; long double d; }u; memset(&u, 0, sizeof(u)); printf("size of void*: %d\n", (int)sizeof(void*)); printf("size of long double: %d\n", (int)sizeof(long double)); u.d = 3; printf("%llg\n", u.d); int i; printf("0x"); for (i = sizeof(u) / sizeof(int) - 1; i >= 0; i--) { printf("%08X ", u.i[i]); } printf("\n"); }