本人非计算机专业,写给自己只为弄清楚这个问题
最近在64位linux系统中打印地址,代码如下
int a = 1;
int *p = &a;
printf("%d\n", sizeof(p));
printf("%p\n", p);
结果为
8
0x7ffea2cabb3c
这就引起我的好奇心了,64位系统应该打印16个字符才对,这里只有12个
我们研究一下sizeof和内存地址为什么是上边打印的这两个东西
我们先来看8位系统中内存表示(8个格,1格1位,1位可以有0和1两种表示),然后再推论64位
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
众所周知 1字节=8bit=8位
sizeof(p) = 系统位数/8;
那么这个8位系统的指针存放地址的字节大小sizeof(p)应该等于1
相应的32位系统地址字节大小sizeof = 4,64位系统地址字节大小sizeof = 8
再来看地址,上边8个格子里表示的内存,最小为00000000=0,最大为11111111=255;
转换为十六进制表示是0x00-0xFF
所以打印出来应该是2个字符,如0xab
那么32位地址打印应该是4*2,8个字符,如0xabababab这样,事实上实验也是这样的
而64位打印出来应该是16个字符,可实际上打印出来只有12个字符
查了查原因,感觉知乎@Rednaxela回答比较专业,这里进行引用
作者:RednaxelaFX
链接:https://www.zhihu.com/question/28638698/answer/41603886
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
假定题主问的只是AMD64。Intel版叫做Intel® 64,是从AMD交叉授权来的AMD64;Intel® 64曾用名EM64T。
当前版本的AMD64架构就规定了只用48位地址;一个表示虚拟内存地址的64位指针只有低48位有效并带符号扩展到64位——换句话说,其高16位必须是全1或全0,而且必须与低48位的最高位(第47位)一致,否则通过该地址访问内存会产生#GP异常(general-protection exception)。
只用48位的原因很简单:因为现在还用不到完整的64位寻址空间,所以硬件也没必要支持那么多位的地址。
设计为带符号扩展的原因也很简单:很多环境中,寻址空间的高一半(higher-half)有特殊用途,而低一半(lower-half)给用户做一般用途。这“高/低”可以通过最高位是1还是0来判断;如果把地址看成带符号整数,那么“负数”部分就是高一半,“正数”部分就是低一半。所以AMD64在设计成只用64位中的48位时,要求canonical form要满足带符号扩展的要求。以后就算允许更多位地址,满足当前限制的地址也仍然会是合法地址,保证了向前兼容性。这些限制都只是临时的。以后真的需要的时候可以放宽到52位,最终时机到的时候就会扩展到真正的完整64位吧。
===============================================
其它64位CPU架构未必有一样的限制。
SPARC的64位版就允许完整的64位寻址空间。
AArch64允许用高8位来做tag,那么还有56位寻址空间。
既然题主问的是48位那多半是AMD64吧⋯
再linux上进行操作
lscpu
架构: x86_64
CPU 运行模式: 32-bit, 64-bit
字节序: Little Endian
Address sizes: 39 bits physical, 48 bits virtual
CPU: 8
在线 CPU 列表: 0-7
每个核的线程数: 1
每个座的核数: 8
座: 1
NUMA 节点: 1
厂商 ID: GenuineIntel
CPU 系列: 6
型号: 158
型号名称: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
步进: 13
CPU MHz: 800.014
CPU 最大 MHz: 4700.0000
CPU 最小 MHz: 800.0000
BogoMIPS: 6000.00
虚拟化: VT-x
L1d 缓存: 256 KiB
L1i 缓存: 256 KiB
L2 缓存: 2 MiB
L3 缓存: 12 MiB
NUMA 节点0 CPU: 0-7
Vulnerability Itlb multihit: KVM: Mitigation: Split huge pages
Vulnerability L1tf: Not affected
Vulnerability Mds: Not affected
Vulnerability Meltdown: Not affected
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp
Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __userpointer sanitization
Vulnerability Spectre v2: Mitigation; Enhanced IBRS, IBPB conditional, RSB filling
Vulnerability Srbds: Mitigation; TSX disabled
Vulnerability Tsx async abort: Mitigation; TSX disabled
标记: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx rdseed adxsmap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities
可以看到虚存有48bits,这也就说明为啥一开始打印的字符数是12个,8位系统2个字符,48位当然是12个啦