int、short、long、long long 的大小?

Size of int, short, long, long long?

根据 C99 §5.2.4.2.1-1 以下类型的大小取决于实现。所说的是它们的大小等于或大于这些值:

short           >= 8 bits
int             >= 16 bits
long            >= 32 bits
long long       >= 64 bits

我一直听说 long 总是 32-bits,而且它严格等同于 int32_t,这看起来是错误的。

什么是真的?

在我的电脑上 long 在 Linux 中是 64 位。

Windows 是唯一在 64 位模式下使用 32 位 long 的主要平台,正是因为现有代码中普遍存在错误假设。这使得在 Windows 上更改 long 的大小变得困难,因此在 64 位 x86 处理器上,long 在 Windows 中仍然是 32 位,以保持各种现有代码和定义的兼容性。

标准的定义是正确的,您对它的解释也是正确的。某些类型的尺寸可能会有所不同。该标准仅规定了这些类型的 minimum 宽度。通常(但不一定)类型 int 与目标处理器具有相同的宽度。

这可以追溯到过去,性能是一个非常重要的方面。每当您使用 int 时,编译器都可以选择仍然保持 至少 16 位的最快类型。

当然,这种做法在今天并不是很好。这只是我们必须忍受的事情。是的,它可以破解代码。因此,如果您想编写完全可移植的代码,请改用 stdint.h 中定义的类型,例如 int32_t 等。或者至少,如果您希望变量保存的数字不在 [−32,767; 32,767].

范围内,则永远不要使用 int

I have always heard that long is always 32-bits and it is strictly equivalent to int32_t which looks wrong.

我很好奇你是从哪里听说的。完全错了。

有很多系统(我认为主要是 16 位或 32 位系统或 64 位 Windows),其中 long 是 32 位,但也有很多long 为 64 位的系统。

(而且即使long是32位,也不一定和[=12=是同一种类型。比如intlong都是32位位,它们仍然是不同的类型,并且 int32_t 可能被定义为其中之一。)

$ cat c.c
#include <stdio.h>
#include <limits.h>
int main(void) {
    printf("long is %zu bits\n", sizeof (long) * CHAR_BIT);
}
$ gcc -m32 c.c -o c && ./c
long is 32 bits
$ gcc -m64 c.c -o c && ./c
long is 64 bits
$ 

如您在问题中所述,对整数类型大小的要求 几乎short 的大小有误)。该标准实际上是根据范围而不是大小来陈述其要求的,但是随着二进制表示的要求意味着最小的位大小。要求是:

  • charunsigned charsigned char:8 位
  • short, unsigned short: 16 位
  • int, unsigned int: 16 位
  • long, unsigned long: 32 位
  • long long, unsigned long long: 64 位

每个有符号类型都有一个范围,其中包括列表中前一个类型的范围。没有上限。

通常 intlong 分别是 32 位和 64 位,特别是在非 Windows 64 位系统上。 (POSIX 要求 int 至少为 32 位。)long long 在我见过的每个系统上正好是 64 位,尽管它可以更宽。

请注意,标准没有为 intshortlong 等类型指定 大小 ,而是这些类型必须能够表示的值的最小范围

例如,一个int必须能够表示至少范围[-32767..32767]1,这意味着它必须 至少 16 位宽。它可能更宽有两个原因:

  • 平台提供了更多的值位来存储更广泛的范围(例如,x86使用32位存储整数值,64位存储长整数);

  • 平台使用 填充位 存储值的一部分以外的内容。

作为后者的一个例子,假设你有一个带有 18 位字的 9 位平台。在 18 位字的情况下,其中两个位是填充位,并且 而不是 用于存储部分值 - 该类型仍然只能存储 [-32767..32767],即使它比 16 位宽。

<stdint.h> header 确实定义了具有特定固定大小(16 位、32 位)的整数类型,但它们可能并非随处可用。


  1. C 不要求对有符号整数进行 2 的补码表示,这就是范围不从 [-32768..32767] 开始的原因。