为什么数据类型的大小会随着操作系统的变化而变化?

在一次采访中我问过这个问题,在某些操作系统中, char大小是2个字节,但在某些操作系统中它是4个字节或不同。

为什么会这样?

为什么它与其他基本类型不同,例如int

这可能是一个棘手的问题。 sizeof(char) 始终为 1。

如果大小不同,可能是因为编译器不合规,在这种情况下问题应该是编译器本身,而不是C或C ++语言。

5.3.3 Sizeof [expr.sizeof]

1 sizeof运算符产生其操作数的对象表示中的字节数 。 操作数是表达式(未计算)或带括号的type-id。 sizeof运算符不应该应用于具有函数或不完整类型的表达式,或者在声明所有枚举数之前应用于枚举类型,或者应用于此类型的带括号的名称,或者应用于指定位字段的左值。 sizeof(char)sizeof(signed char)sizeof(unsigned char)是1.应用于任何其他基本类型(3.9.1)的sizeof的结果是实现定义的。 (强调我的)

除指出的类型之外的其他类型的大小是实现定义的,并且它们因各种原因而变化。 如果int以64位而不是32位表示,则int具有更好的范围,但是在32位体系结构上它也更高效为32位。

类型的物理大小(以位数表示)通常由目标硬件决定。

例如,某些CPU只能以不小于16位的单位访问内存。 为了获得最佳性能,可以将char定义为16位整数。 如果你想在这个CPU上使用8位字符,编译器必须生成额外的代码,用于将8位值打包到16位存储单元和从16位存储单元解包。 额外的打包/解包代码将使您的代码更大更慢。

而这不是它的结束。 如果将16位存储器单元细分为8位字符,则可以有效地在地址/指针中引入一个额外的位。 如果CPU中的普通地址是16位,那么你在哪里添加额外的第17位? 有两种选择:

  • 使指针更大(32位,其中15个未使用)并浪费内存并进一步降低速度
  • 将可寻址地址空间的范围缩小一半,浪费内存,并降低速度

后一种选择有时可行。 例如,如果整个地址空间被分成两半,其中一个由内核使用,另一个由用户应用程序使用,则应用程序指针将永远不会在其地址中使用一位。 您可以使用该位选择16位存储器单元中的8位字节。

C被设计为在尽可能多的不同CPU上运行。 这就是为什么charshortintlonglong longvoid*void(*)()floatdoublelong doublewchar_t等的物理大小可能会有所不同。

现在,当我们在为不同的编译器讨论不同的物理尺寸时,为同一个CPU生成代码,这就变成了一种随意的选择。 但是,它看起来可能不是那么随意。 例如,Windows的许多编译器定义int = long = 32位。 他们这样做是为了避免程序员在使用Windows API时产生混淆,因为期望INT = LONG = 32位。 由于失去了程序员的注意力,将intlong定义为其他因素会导致错误。 因此,编译器必须在这种情况下效仿。

最后,C(和C ++)标准使用charsbytes 。 它们在大小方面是相同的概念。 但是C的字节不是典型的8位字节,它们可以合法地大于前面解释的字节。 为避免混淆,您可以使用术语octet ,其名称表示数字8.许多协议使用此字来实现此目的。