非常感谢所有参与寻找答案的人。
大多数回复都分享了我已经学到的东西,但一些 cmets 提供了非常有趣的见解。
下面我将总结一下我目前学到的东西(供我以后参考)。
结论
看起来像 C(截至 C17 [C17_N2176] 的最新草案)不保证
sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
(相对于C++)。
什么是保证
以下是我自己对 C保证关于整数类型的解释/总结(对不起,如果我的术语不够严格)。
同一类型的多个别名
This topic 将同一类型的多个别名移开([C17_N2176],6.2.5/4 括号内的句子指的是 6.7.2/2,感谢@M.M 的参考)。
一个字节的位数
字节中的位数是特定于实现的,为>= 8。它由CHAR_BIT 标识符确定。
5.2.4.2.1/1 整数类型的大小<limits.h>
它们的实现定义值应在幅度(绝对值)上与显示的值相同或更大,符号相同。
非位域的最小对象的位数(字节)
CHAR_BIT 8
下面的文本假定字节为 8 位(请记住字节具有不同位数的实现)。
sizeof([[un]signed] char)
sizeof(char)、sizeof(unsigned char)、sizeof(signed char),均为 1 个字节。
6.5.3.4/2 sizeof 和 _Alignof 运算符
sizeof 运算符产生其操作数的大小(以字节为单位)
6.5.3.4/4:
当sizeof 应用于类型为char、unsigned char 或signed char 的操作数时,
(或其合格版本)结果为 1。
值的范围和类型的大小
对象可能不会使用所有位来存储值
对象表示具有值位,可能具有填充位,并且对于有符号类型只有一个符号位(6.2.6.2/1/2 整数类型)。
例如。变量可以有 4 个字节的大小,但只有 2 个最低有效字节可用于存储值
(对象表示只有 16 个值位),类似于 bool 类型至少有 1 个值位,所有其他位都是填充位。
取值范围与类型大小(或取值位数)的对应关系可论证。
一方面@eric-postpischil 指的是 3.19/1:
价值
当解释为具有特定类型时,对象内容的精确含义
这给人的印象是每个值都有一个唯一的位表示(位模式)。
另一方面,@language-lawyer 声明
不同的值不必由不同的位模式表示。因此,可能有比可能的位模式更多的值。
当标准与委员会回应 (CR) 之间存在矛盾时,委员会回应由实施者选择。
来自 DR260 委员会的回应表明对象表示中的位模式并不能唯一地确定值。
不同的值可以由相同的位模式表示。所以我认为CHAR_BIT == 8 和sizeof(int) == 1 的实现是可能的。
我没有声称一个对象同时具有多个值
@language-lawyer 的陈述给人的印象是多个值(例如5、23、-1),可能在不同的时间,
可以对应相同的位模式(例如0xFFFF)
变量的值位。如果这是真的,那么除[[un]signed] char 之外的整数类型(请参阅上面的“sizeof([[un]signed] char)”部分)可以具有任何字节大小>= 1
(它们必须至少有一个值位,这会阻止它们具有字节大小0(严格来说是偏执的),
这导致大小至少为一个字节),
并且整个值范围(由<limits.h> 规定,见下文)可以对应于“至少一个值位”。
总而言之,sizeof(short)、sizeof(int)、sizeof(long)、sizeof(long long) 之间的关系可以是任意的
(其中任何一个,以字节大小计,都可以大于或等于其他任何一个。同样,严格来说有点偏执)。
什么似乎没有争议
没有提到的是 6.2.6.2/1/2 整数类型:
对于无符号整数类型..如果有
N 个值位,每个位应代表 1 和 2^(N-1) 之间的 2 的不同幂,以便
该类型应该能够使用纯二进制表示来表示从 0 到 2^N - 1 的值..
对于有符号整数类型.. 作为值位的每个位都应具有
与对应无符号类型的对象表示中的相同位相同的值..
这让我相信每个值位都会为对象的整体价值添加一个独特的值。例如。最低有效值位(我将其称为值位编号 0)(无论它位于字节中的哪个位置)添加一个值 2^0 == 1,并且 没有任何其他值位添加value,即添加的值唯一。
值位编号 1(同样,无论其在字节中的位置如何,但位置与任何其他值位的位置不同)唯一地添加了一个值 2^1 == 2。
这两个值位加起来就是总绝对值 1 + 2 == 3。
这里我不会深入探讨当 设置为 1 或 清除为 0 或两者的组合时它们是否添加值。
在下面的文本中,我假设如果设置为 1,它们会增加值。
以防万一我还要引用 6.2.6.2/2 整数类型:
如果符号位为1,则该值应通过以下方式之一进行修改:
...
— 符号位的值为 -(2^M) (二进制补码);
在 6.2.6.2/2 之前的版本中,已经提到 M 是有符号类型中值的位数。
因此,如果我们谈论的是具有 7 个值位和 1 个符号位的 8 位有符号值,那么符号位如果设置为 1,则添加 -(2^M) == -(2^7) = 的值= -128。
之前我考虑了一个示例,其中两个最低有效值位的总和为 3 的总绝对值。
再加上 7 个值位的 8 位有符号值的符号位设置为 1,总的有符号值将为 -128 + 3 == -125。
例如,该值可以具有 0x83 的位模式(符号位设置为 1 (0x80),两个最低有效值位设置为 1 (0x03),如果是,则两个值位都添加到整体值中)在二进制补码表示中设置为 1,而不是清零)。
这个观察让我觉得,很可能,存在一对一的对应关系
在值的范围和对象中的值位的数量之间 - 每个值都有一个唯一的值位模式和每个值位模式唯一地映射到单个值。
(我意识到这个中间结论仍然可能不够严格或错误或不涵盖某些情况)
值位和字节的最小数目
5.2.4.2.1/1 整数类型的大小<limits.h>:
重要的句子:
它们的实现定义的值应等于或大于在幅度(绝对值)上与所示值相同,符号相同。
然后:
SHRT_MIN -32767 // -(2^15 - 1)
SHRT_MAX +32767 // 2^15 - 1
USHRT_MAX 65535 // 2^16 - 1
这告诉我
short int 有至少 15 个值位(参见上面的SHRT_MIN、SHRT_MAX),即至少 2 个字节 (如果字节是 8 位,请参见上面的“字节中的位数”)。
unsigned short int 有至少 16 个值位(上面的USHRT_MAX),即至少 2 个字节。
继续该逻辑(参见 5.2.4.2.1/1):
int 具有至少 15 个值位(参见 INT_MIN、INT_MAX),即 至少 2 个字节。
unsigned int 具有至少 16 个值位(参见 UINT_MAX),即至少 2 个字节。long int 具有至少 31 个值位(参见 LONG_MIN、LONG_MAX),即至少 4 个字节。
unsigned long int 具有 至少 32 个值位(参见 ULONG_MAX),即至少 4 个字节。
long long int 具有至少 63 个值位 (参见LLONG_MIN、LLONG_MAX),即至少8个字节。
unsigned long long int有至少64个值位(参见ULLONG_MAX),即至少 8 个字节。
这向我证明:
1 == sizeof(char) sizeof(short),sizeof(int),sizeof(long),sizeof(long long)}。
sizeof(int)
6.2.5/5 种类型
“普通”int 对象具有执行环境的架构建议的自然大小(大到足以包含INT_MIN 到INT_MAX 范围内的任何值,如标题<limits.h>)。
这向我证明:
sizeof(int) == 4 在 32 位架构上(如果字节是 8 位),
sizeof(int) == 8 在 64 位架构上(如果字节是 8 位)。
sizeof(unsigned T)
6.2.5/6 种类型
对于每个有符号整数类型,都有一个对应的(但不同的)无符号整数类型(用关键字unsigned 指定)使用相同的存储量(包括符号信息)并且具有相同的对齐要求。
这向我证明了:
sizeof(unsigned T) == sizoef(signed T).
值的范围
6.2.5/8 种类型
对于任何两个具有相同符号和不同整数转换等级的整数类型(见6.3.1.1),具有较小整数转换等级的类型的值范围是另一个类型的值的子范围。
(见下文 6.3.1.1 的讨论)
我假设一个值的子范围可以包含与该范围相同或更少个值。
IE。与具有较高转换等级的类型相比,具有较小转化等级的类型可以具有相同或更少个值。
6.3.1.1/1 布尔值、字符和整数
——long long int的等级大于long int的等级,大于int的等级,大于short int的等级,大于signed char的等级。
— 任何无符号整数类型的等级应等于相应的有符号整数类型的等级,如果有的话。
— _Bool 的排名应小于所有其他标准整数类型的排名。
— 任何枚举类型的等级应等于兼容整数类型的等级(见 6.7.2.2)。
这告诉我:
range_of_values(bool) <= range_of_values(signed char) <= range_of_values(short int) <= range_of_values(int) <= range_of_values(long int) <= range_of_values(long long int).
对于 unsigned 类型,值范围之间的关系是相同的。
这为类型中的值位的数量建立了相同的关系。
但仍不能证明这些类型对象的字节大小之间存在相同的关系。
IE。 C(截至[C17_N2176])不保证以下语句(相对于C++):
sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)