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

时间:2016-06-10 13:50:51

标签: c c11 c89

我知道sizeof(char)将始终为1,并且这是以字节为单位的,并且一个字节可以是任意数量的位(我相信任何位数大于或等于8,但不是积极的)。

我也经常看到提及C数据类型大小如何根据它们的大小之间的关系来指定的引用,例如“sizeof(int)< = sizeof(long)”。

我的问题基本上是:“sizeof(int)”在一个字节为8位且int为39位(或其他一些不能被CHAR_BIT整除的值)的系统上进行评估。

我的猜测是sizeof()返回存储类型所需的最小字节数,因此它将向上舍入到下一个字节。因此,在我的39位int示例中,sizeof(int)的结果为5。

这是对的吗?

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

谢谢!

3 个答案:

答案 0 :(得分:3)

人们经常无法理解的是,在C中,sizeof和“宽度”之间存在明显的区别。

“width”更多关于二进制表示,范围,溢出/环绕行为。你说无符号整数类型是16位宽,那么你的意思是它包围在65535.

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

由于这个原因,尝试在sizeof类型和类型的算术行为之间找到连接是没有意义的:类型可以有一定的范围,但可以占用它想要的任何存储空间。

回答你的问题(“如果在8位字符机器上使用39位int怎么办?”)我想以TI C6400 +为例,因为它有一个40位{{1}和8位字符,非常接近。

TI C6400 +是一个字节可寻址机器,因此它必须将8位字节定义为long

它还有一个40位整数类型,因为ALU可以在40位整数上运行,并且它们将其定义为char

你会认为long应该是5,对吗?

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

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

<强>更新

回到“39位”的情况。

由于6.2.8.1要求所有完整类型的对齐是“bytes”的整数倍,因此如果long long为8,则必须将39位整数填充到至少40位或更大,因此{ {1}}此类型必须是大于或等于5的整数。

答案 1 :(得分:1)

Chapter and verse

6.2.6类型表示

6.2.6.1概述

  1. 除本条款所述外,所有类型的陈述均未指明。
  2. 除了位字段外,对象由一个或多个字节的连续序列组成, 其数量,顺序和编码是明确指定的 实现定义。
  3. 存储在无符号位域和unsigned char类型对象中的值应为 使用纯二进制表示法表示。 49)
  4. 存储在任何其他对象类型的非位字段对象中的值由n × CHAR_BIT组成 位,其中n是该类型对象的大小,以字节为单位。该值可以复制到 类型unsigned char [n]的对象(例如,memcpy);得到的字节集是 称为值的对象表示。存储在位字段中的值由m位组成, 其中m是为位字段指定的大小。对象表示是m的集合 比特字段包含在保持它的可寻址存储单元中。两个值(其他 比NaNs)具有相同的对象表示比较相等,但比较的值 等于可以具有不同的对象表示。
49)使用二进制数字0和1的整数的位置表示,其中包含值 由连续位表示的是加法的,以1开始,并乘以连续的积分 2的幂,除了位置最高的位。 (改编自美国国民 信息处理系统字典。)一个字节包含CHAR_BIT位,以及值 类型unsigned char的范围从02^CHAR_BIT − 1
  

我的问题基本上是:“sizeof(int)”在一个字节为8位且int为39位(或其他一些不能被CHAR_BIT整除的值)的系统上评估为什么。

实现必须将CHAR_BIT大小的存储单元映射到奇数大小的单词上,以满足上述要求,可能会带来显着的性能损失。 39位字最多可容纳4个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个字符。

答案 2 :(得分:0)

  

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

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

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运算符

  

sizeof运算符产生其操作数的大小(以字节为单位)   可以是表达式或类型的带括号的名称。大小是   根据操作数的类型确定。结果是整数。   [...]

为了增加您的困惑,在CHAR_BIT = 32的计算机上,sizeof(int16_t)将为1,因此sizeof(int32_t)也是如此,您实际上最终可能会分配更多的内存字节如果您使用malloc(sizeof(int16_t) * n)代替malloc(sizeof(int16_t[n]),则需要(我不确定)。