当前位置: 首页 > 科技观察

你知道32位程序和64位程序的区别吗?

时间:2023-03-13 21:59:40 科技观察

本文转载自微信公众号“编程明珠”,转载请联系编程明珠公众号。作者:守望,linux应用开发者,目前在公众号【编程明珠】上分享Linux/C/C++/数据结构与算法/工具等原创技术文章和学习资源。我们在写C/C++程序的时候,32位程序和64位程序的代码有什么区别?如何编写既能编译成32位程序又能编译成64位程序的代码?代码上的区别其实是,对于32位程序和64位程序来说,代码上并没有太大的区别,严格来说,甚至是一样的。主要区别是一些基本数据类型占用的字节长度不同(注意:这只是针对类Unix平台)type32位占用字节64位占用字节long48unsignedlong48pointer48的当然这里的long包括了它定义的一些类型,比如time_t,它的长度也是不一样的。关于time_t,有一个有趣的问题《什么是2038问题》。此外,默认的对齐字节数也不同。32位程序默认为4字节,64位程序默认为8字节。字节对齐请参考《理一理字节对齐的那些事》。让我们举个小例子看看它们之间的区别。//来源:公众号编程珠玑//作者:看守先生test.c#includestructTest{inta;longb;};intmain(void){printf("sizeof(long)=%zu\n",sizeof(long));//long类型占用的字节数printf("sizeof(unsignedlong)=%zu\n",sizeof(unsignedlong));//unsignedlong类型占用的字节数typestructTesttest={1,2};printf("sizeof(structTest)=%zu\n",sizeof(test));//用来测试对齐的字节数printf("sizeof(pointer)=%zu\n",sizeof(&test));//指针占用的字节数return0;}如果你的系统是64位的,默认会编译成64位程序,如果需要编译作为32位程序,需要带上-m32参数,如果你的系统是32位的,那么不能直接运行64位程序,但是如果是64位,则可以运行32位程序.(其实下载软件需要选择位数的时候需要注意,如果你的系统是32位的,但是你下载的是64位的程序包,自然是不可用的,反之就是是的。)编译为32位程序并运行:$gcc-otest32test.c-m32$./test32sizeof(long)=4sizeof(unsignedlong)=4sizeof(structTest)=8sizeof(pointer)=4编译并运行64-位程序:$gcc-otest64test.c$./test64sizeof(long)=8sizeof(unsignedlong)=8sizeof(structTest)=16sizeof(pointer)=8通过运行结果,我们也可以看出上面所说的区别。那么可执行文件本身有什么区别呢?$readelf-htest32ELFHeader:Magic:7f454c46010101000000000000000000Class:ELF32Data:2'scomplement,littleendianVersion:1(current)OS/ABI:UNIX-SystemVABIVersion:0Type:EXEC(Executablefile)Machine:Intel8038..)可以看到识别到Class属性作为ELF32。而对于64位:readelf-htest64ELFHeader:Magic:7f454c46020101000000000000000000Class:ELF64Data:2'scomplement,littleendianVersion:1(current)OS/ABI:UNIX-SystemVABIVersion:0Type:EXEC(Executablefile)Machine:AdvancedMicro64X确实有很多属性通过自读的信息。比如你交叉编译后出现链接错误或者最终执行的程序无法在目标机器上运行,你可以查看Machine部分看程序是否可以在你想要的平台上运行。比如AdvancedMicroDevicesX86-64在64位程序中显示在Machine中,至少说明在arm平台上不能正常运行。一个程序最多可以申请多少内存空间?还记得这个面试问题吗?如果你只回答Linux理论不超过3G,windows不超过G,那肯定是不完整的。这里要区分32位程序和64位程序。程序。这一点在《解引用NULL为什么会挂死?》中已经提到了。32位决定了它的虚拟地址空间的最大值为2^32,即4G。除去操作系统占用的1G左右,剩下的3G左右3G左右。当然3G包含了所有的代码,数据等等,总结就是最后能用到的不超过3G。小于3G地址空间。(这里注意不是说只能访问电脑4G的内存,而是说最大可寻址范围是4G)。那么64位的虚拟地址空间就扩展到了17179869184G,那么,你看出区别了吗?通过上面的简单分析可以发现,64位程序理论上可以使用的内存是惊人的,而32位程序则非常有限。另外,在《什么是2038问题》”中提到的另一个问题就是2038之后,32位程序将很难正常使用时间相关的处理。当然64位系统通常可以支持更高精度浮点运算.同时支持32位和64位代码编写原则基于上面提到的原因,很多传统系统开始移植到64位系统,如果原来的代码很规范,那么移植工作就相对简单了easy,链接64位库,可以编译成64位程序,但是如果不遵循以下原则,那么工作量会比较大:依赖long类型和指针类型占用空间的大小以及它们的表示范围当然,对于这个原理,可能有很多表现形式。混合long和int比如:voidtest(longlen){intlocalLen=len;xxxx;}很明显,截断可能会在这里找到。最常见的一种是:intlen=sizeof(xxx);当然e,这里大部分情况下不会有大问题,直到它的长度大于int表示的范围。谨慎使用掩码定义我们可能经常需要定义一些掩码:longmask=OxFFFFFFFFFL;在32位系统上,这将设置所有位(每个位都为1),但在64位系统上,仅设置低32位。原来这个值是0x00000000FFFFFFFF。如果你想让所有位置都为1,那么你可以:longmask=1L<<((sizeof(long)*8)-1);打印指针32次,这没问题:inta=10;int*p=&a;printf("%x",p);但是在64位下,打印不完整。很自然地使用:printf("%p",p);在32位和64位系统中传输结构数据,默认的对齐字节数是不同的。strcuttest{inta;longb;}如果对方是64位的,发送上面的结构数据,而你的程序是32位的,可想而知结果不会如你所愿。前者占用16字节空间,后者占用8字节空间。显示定义long如果你的数据类型是long,可以用L来显示描述:longi=1<