是否保证每个 C 数据类型的大小都是字节的整数倍?

Is the size of every C data type guaranteed to be an integer multiple of bytes?

我知道 sizeof(char) 永远是 1,而且这是以字节为单位的,一个字节可以是任意位数(我相信大于或等于 8 的任意位数,但对此并不乐观。

我也经常看到提到如何根据大小之间的关系来指定 C 数据类型大小的参考资料,例如 "sizeof(int) <= sizeof(long)"。

我的问题基本上是:"sizeof(int)" 在一个 byte 是 8 位而 int 是 39 位(或其他不能被 CHAR_BIT 整除的值)的系统上计算什么).

我的猜测是 sizeof() returns 存储类型所需的最小字节数,因此它会四舍五入到下一个字节。所以在我使用 39 位 int 的示例中,sizeof(int) 的结果将是 5.

这是正确的吗?

此外,是否有一种简单的方法可以确定特定类型可以容纳的位数,即 100% 可移植并且不需要包含任何 headers?这更像是一种学习体验,而不是实际应用。我只会在实践中使用 stdint 类型。我在想可能是沿着声明变量并将其初始化为 ~0,然后循环并左移它直到它为零的方式。

谢谢!

Is the size of every C data type guaranteed to be a multiple of bytes?

是的。即使表示数据类型所需的位数小于 CHAR_BIT,例如 struct foo { unsigned int bar : 1};int16_tCHAR_BIT = 32.

的系统上
sizeof(char) = 1 (guaranteed)
CHAR_BIT >= 8 ( = 8 on posix compliant system)
sizeof(anything else) = k * sizeof(char) = k where k is a whole number

来自 6.5.3.4 sizeof 和 _Alignof 运算符

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. [...]

让您更加困惑的是,在 CHAR_BIT = 32 的机器上,sizeof(int16_t) 将是 1,sizeof(int32_t) 也将是 1,您最终可能会分配更多字节的如果您使用 malloc(sizeof(int16_t) * n) 而不是 malloc(sizeof(int16_t[n]).

,则内存超出要求(虽然我不确定)

Chapter and verse:

6.2.6 Representations of types

6.2.6.1 General

  1. The representations of all types are unspecified except as stated in this subclause.
  2. Except for bit-fields, objects are composed of contiguous sequences of one or more bytes, the number, order, and encoding of which are either explicitly specified or implementation-defined.
  3. Values stored in unsigned bit-fields and objects of type unsigned char shall be represented using a pure binary notation.49)
  4. Values stored in non-bit-field objects of any other object type consist of <em>n</em> × CHAR_BIT bits, where <em>n</em> is the size of an object of that type, in bytes. The value may be copied into an object of type unsigned char [n] (e.g., by memcpy); the resulting set of bytes is called the object representation of the value. Values stored in bit-fields consist of <em>m</em> bits, where <em>m</em> is the size specified for the bit-field. The object representation is the set of <em>m</em> bits the bit-field comprises in the addressable storage unit holding it. Two values (other than NaNs) with the same object representation compare equal, but values that compare equal may have different object representations.

49) A positional representation for integers that uses the binary digits 0 and 1, in which the values represented by successive bits are additive, begin with 1, and are multiplied by successive integral powers of 2, except perhaps the bit with the highest position. (Adapted from the American National Dictionary for Information Processing Systems.) A byte contains CHAR_BIT bits, and the values of type unsigned char range from 0 to 2^CHAR_BIT − 1.

My question is basically: What would "sizeof(int)" evaluate to on a system where a byte is 8 bits and an int is 39 bits (or some other value which is not evenly divisible by CHAR_BIT).

实施必须将 CHAR_BIT 大小的存储单元映射到奇数大小的单词,以便上述要求成立,可能会带来显着的性能损失。一个 39 位字最多可以容纳四个 8 位或 9 位存储单元,因此 sizeof (int) 可能 计算为 4。

或者,实施者可以简单地决定它不值得麻烦并将 CHAR_BIT 设置为 39; 所有内容,包括单个字符,占用一个或多个完整的单词,根据类型,最多有 31 位未使用。

过去有过这类事情的现实例子。一个旧的 DEC PDP(我想说 PDP-8,也许是 PDP-11?)使用 36 位字和 7 位 ASCII 作为字符值;一个字可以存储 5 个字符,其中一位未使用。所有其他类型都占用了一个完整的词。如果实现将 CHAR_BIT 设置为 9,您可以将 CHAR_BIT 大小的存储单元干净地映射到 36 位字,但同样,如果 硬件 每个单词需要 5 个字符。

人们常常不理解的是,在C 中,sizeof 和"width" 之间有明显的区别。

"width" 更多关于二进制表示、范围、overflow/wrap-around 行为。你说一个无符号整数类型是 16 位宽那么你的意思是它在 65535 处回绕。

然而 sizeof 只关心存储。因此 sizeof(T[n])==sizeof(T)*n 通过允许 sizeof 包含填充来维护。

因此,试图找到 sizeof 类型与类型的算术行为之间的联系毫无意义:类型可以有一定的范围,但可以占用任何存储空间 space想要。

回答你的问题("what if a 39-bit int on a 8-bit-char machine?")我想以TI C6400+为例,因为它有40位long和8位字符,非常接近。

TI C6400+是字节寻址机器,所以它必须定义8位字节为char

它还有一个40位整数类型,因为ALU可以对40位整数进行运算,他们定义为long

你会觉得sizeof(long)应该是5吧?

嗯,它可以,但是这个 CPU 也不能很好地支持未对齐加载,所以出于性能原因,这个 long 类型默认对齐到 8 字节边界而不是 5 -byte,那么每个 long 都有 3 个字节的填充(在内存和寄存器级别,因为它在 CPU 中也需要一对 GPR),然后 sizeof(long) 自然变成 8。

有趣的是,C6400+ C 实现还提供 long longsizeof(long long) 也是 8。但这是真正的 64 位宽类型,具有完整的 64 位范围,而不是 40 位。

更新

所以回到“39 位”的情况。

由于6.2.8.1要求所有完整类型的对齐都是"bytes"的整数倍,那么如果CHAR_BIT是,则39位整数必须至少填充到40位或更大8,所以sizeof这样的类型必须是大于等于5的整数。