在 C11 [C11_N1570]和 C17 [C17_N2176]的后期草稿中,我找不到以下证明(我相信,这是众所周知的):
sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
有人可以向我推荐特定的部分吗?
我知道 C++11 的这个回复。回复的第二部分谈到了 C,但只涉及values 的范围。它不能证明字体大小之间的比例。
在 C11 [C11_N1570]和 C17 [C17_N2176]的后期草稿中,我找不到以下证明(我相信,这是众所周知的):
sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
有人可以向我推荐特定的部分吗?
我知道 C++11 的这个回复。回复的第二部分谈到了 C,但只涉及values 的范围。它不能证明字体大小之间的比例。
6.2.6.2 Integer Types
首先定义子类型的值和填充位unsigned
(除了unsigned char
)。
除了根本不必有任何填充位之外,没有太多关于填充位的说法。但可能不止一个,这与有符号类型的符号位不同。
没有常识规则反对过度填充 ashort
直到它比 along
长,无论 long 是否具有更多值位。
(值)位数与最大值之间的直接隐含关系也显示在标题中5.2.4.2.1 Sizes of integer types <limits.h>
。这定义了最小最大值,而不是对象大小(CHAR_BIT 除外)。
其余的在于名称本身和实现的手中:short
and long
,not small
and large
。说“我是一个节省空间的整数”比说“我是一个最大值减小的整数”更好。
非常感谢所有参与寻找答案的人。大多数回复都分享了我已经学到的东西,但一些评论提供了非常有趣的见解。
下面我将总结到目前为止我学到的东西(供我自己将来参考)。
看起来 C (截至 C17 [C17_N2176]的最新草案)并不能保证这一点
sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
(与C++相反)。
以下是我自己对 C 对整数类型所做保证的解释/总结(抱歉,如果我的术语不够严格)。
这个话题让我不再使用同一类型的多个别名([C17_N2176],6.2.5/4 括号内的句子指的是 6.7.2/2,感谢@MM 的参考)。
字节中的位数是特定于实现的,并且是>= 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/2sizeof
和_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:
value
当解释为具有特定类型时,对象内容的精确含义
这给人的印象是每个值都有唯一的位表示(位模式)。
另一方面,@language-lawyer 指出
不同的值不必由不同的位模式表示。因此,可能有比可能的位模式更多的值。
当标准与委员会回应 (CR) 之间存在矛盾时,委员会回应由实施者选择。
来自 DR260 委员会的回应表明,对象表示中的位模式并不能唯一地确定值。不同的值可以由相同的位模式表示。所以我认为
CHAR_BIT
== 8 和sizeof(int)
== 1 的实现是可能的。
我没有声称一个对象同时具有多个值
@language-lawyer 的陈述给人的印象是多个值(例如5
, ) 23
,-1
可能在不同的时刻,可以对应于0xFFFF
变量的值位的相同位模式(例如 )。如果这是真的,那么除[[un]signed] char
(参见sizeof([[un]signed] char)
上面的“The”部分)之外的整数类型可以有任何字节大小>= 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
,并且没有任何其他值位添加该值,即值是唯一添加的。值位编号 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 位,请参见上面的“字节中的位数”)。至少有 16 个值位
unsigned short int
(以上),即至少 2 个字节。USHRT_MAX
继续该逻辑(见 5.2.4.2.1/1):至少有 15 个值位
int
(见, ),即至少 2 个字节。至少有 16 个值位(参见),即至少 2 个字节。至少有 31 个值位(见, ),即至少 4 个字节。至少有 32 个值位(参见),即至少 4 个字节。至少有 63 个值位(参见, ),即至少 8 个字节。至少有 64 个值位(参见INT_MIN
INT_MAX
unsigned int
UINT_MAX
long int
LONG_MIN
LONG_MAX
unsigned long int
ULONG_MAX
long long int
LLONG_MIN
LLONG_MAX
unsigned long long int
ULLONG_MAX
),即至少 8 个字节。
这向我证明:
1 == sizeof(char)
< { sizeof(short)
, sizeof(int)
, sizeof(long)
, sizeof(long long)
} 中的任何一个。
sizeof(int)
6.2.5/5 类型
“普通”
int
对象具有执行环境架构所建议的自然大小(大到足以包含在 header 中定义的范围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 的讨论)
我假设值的子范围可以包含与范围相同或更少数量的值。即具有较小转换等级的类型可以具有与具有较大转换等级的类型相同或更少数量的值。
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)
.
对于无符号类型,值范围之间的关系是相同的。
这为类型中的值位数建立了相同的关系。
但仍然不能证明这些类型的对象的字节大小之间的相同关系。
即 C(截至[C17_N2176])不保证以下语句(与 C++ 相对):
sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
从 ISO/IEC 9899:2017 的初步检查(您的 C17 C17_N2176链接):
<limits.h>
具有(+ 或 -)(2 提升为 n)-1 信息(指示该类型的位数)的范围。<limits.h>
)。这让我认为范围指定了该类型可以是最小的位大小。也许某些架构分配的大小大于这个最小大小。
相关部分是:
环境限制和limits.h
,来自 C17 5.2.4.2.1“整数类型 <limits.h> 的大小”。如果我们只看无符号类型,那么实现至少需要支持的最小值是:
UCHAR_MAX 255
USHRT_MAX 65535
UINT_MAX 65535
ULONG_MAX 4294967295
ULLONG_MAX 18446744073709551615
然后检查有关整数转换等级的 C17 6.3.1.1 部分(另请参阅隐式类型提升规则):
- 的等级
long long int
应大于 的等级long int
应大于 的等级int
应大于 的等级short int
应大于 的等级signed char
。- 任何无符号整数类型的等级应等于相应的有符号整数类型的等级,如果有的话。
最后,C17 6.2.5/8 是规范性文本,说明具有较低转换等级的每个类型都是较大等级类型的子集:
对于任何两个具有相同符号和不同整数转换等级的整数类型(见 6.3.1.1),具有较小整数转换等级的类型的值范围是另一个类型的值的子范围。
为了满足这个要求,我们必须有:
sizeof(unsigned char) <=
sizeof(unsigned short) <=
sizeof(unsigned int) <=
sizeof(unsigned long) <=
sizeof(unsigned long long)