为什么 C 数据类型在这台机器上有这些特定的大小?

Why do C datatypes have these specific sizes on this machine?

我注意到 C 数据类型的大小 may vary。我想知道是什么原因导致这台机器生产的特定尺寸:

$ cat sizes.c
int main()
{
    printf("void *:%ld\n", sizeof(void *));
    printf("char:%ld\n", sizeof(char));
    printf("short:%ld\n", sizeof(short));
    printf("int:%ld\n", sizeof(int));
    printf("long:%ld\n", sizeof(long));
    printf("long long:%ld\n", sizeof(long long));
    printf("float:%ld\n", sizeof(float));
    printf("double:%ld\n", sizeof(double));
    printf("long double:%ld\n", sizeof(long double));

    return 0;
}

$ ./sizes
void *:8
char:1
short:2
int:4
long:8
long long:8
float:4
double:8
long double:16

是否因为我的机器是:

以下是系统详细信息:

$ uname -a
Linux melancholy 3.13.0-46-generic #77-Ubuntu SMP Mon Mar 2 18:23:39 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/issue
Ubuntu 14.04.2 LTS \n \l

$ cat /proc/version
Linux version 3.13.0-46-generic (buildd@tipua) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #77-Ubuntu SMP Mon Mar 2 18:23:39 UTC 2015

$ cat /proc/cpuinfo 
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 60
model name      : Intel(R) Core(TM) i5-4460  CPU @ 3.20GHz
stepping        : 3
microcode       : 0x12
cpu MHz         : 3201.000
cache size      : 6144 KB
physical id     : 0
siblings        : 4
core id         : 0
cpu cores       : 4
apicid          : 0
initial apicid  : 0
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
flags           : 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 arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid
bogomips        : 6400.67
clflush size    : 64
cache_alignment : 64
address sizes   : 39 bits physical, 48 bits virtual
power management:

... Another three identical processors ...

澄清一下,我并不是在暗示系统有任何问题。相反,我想知道为什么值是它们的值,以便我可以预测它们在哪些系统上会有所不同,以便我可以编写可移植代码。

我想可以肯定地说,从实际的角度来看,驱动力可能是处理器。

处理器的相关架构无疑会对 int 的大小是否确实发生变化产生影响,但如果您的目标是超过 1 个特定处理器(例如,intel i3 530),那么您将需要记住它。

32 位英特尔奔腾与 64 位英特尔奔腾。

phone 中的 Arm 9 与台面 POS 机中的 Arm 11。

等等

处理此问题的一种方法是使用 int32_t、uint64_t 和朋友。在可用的情况下,这些将保证具有相同的大小:uint32_t 等的 32 位..

那里的模型是LP64,意思是pointers和long是64位的;这是 Linux 和更多平台上的 AMD64 标准;另一个是 Windows LLP64,其中只有 long long 是 64 位宽而 long 是 32 位。

通常的选择是:char是最小的可寻址单元,最好是8位。 sizeof(short) 至少为 2;如果处理器支持这个,那就这样吧。 int 通常被选为 最快的 整数类型 - 在 64 位模式下的 AMD64 架构上,32 位寄存器比 16 位或 64 位寄存器使用起来更快,或者支持更多-位寄存器(16 位和 64 位寄存器模式需要前缀字节)。

现在 Windows 使用 LLP64 的原因是兼容性 - 许多代码错误地假设 long 是 32 位;同样在 Unix 世界中,假设指针适合 long - 现在指针是 64 位,那么 long 必须匹配该宽度。


要编写可移植程序,请包含 <inttypes.h> 并在那里使用常量;否则假设这些类型是它们的最小大小(int 2 字节等)。将 intptr_t/uintptr_t 用于整数变量,这些变量也应该足够宽以容纳指针 - 或者使用联合。