【问题标题】:Which sections of the C standard prove the relation between the integer type sizes?C 标准的哪些部分证明了整数类型大小之间的关系?
【发布时间】:2021-05-21 05:20:24
【问题描述】:

在 C11 [C11_N1570] 和 C17 [C17_N2176] 的后期草稿中,我找不到以下证明(我相信这是众所周知的):
sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
任何人都可以参考我的特定部分吗?

我知道 C++11 的 this reply。回复的第二部分谈到了 C,但只涉及 值的范围。它不能证明 类型大小之间的比率

【问题讨论】:

  • 值的范围应该足以得出关于类型各自大小的结论,不是吗?
  • §5.2.4.2... 范围规定 大小,但仅与特定 ISA 相关。其他一切都是主观的。由于设置了范围,因此设置了大小。
  • @tadman:指定范围。但是我们是否可以有一个 DeathStation 9000 实现,其中 USHRT_MAX 是 65536,UINT_MAX4294967296,但 sizeof(unsigned int) == 4sizeof(unsigned short) = 27 由于大量填充位?这会非常愚蠢,但我不确定这是否违法。
  • @tadman:我相信值的范围和类型大小是不相关的(直到证明相反)。类型可以更大(8 个字节),但值的范围更小(仅占用 2 个最低有效字节)。另一种类型可以更小 - 4 个字节 - 但具有更大的值范围 - 占用所有 4 个字节。
  • 我认为标准只保证sizeof(X) >= 1 和给定类型的最小数量的非填充位。理论上,应该可以有 4 字节长的 short 和 16 个填充位和 2 字节长的 int 没有填充。虽然符合 C 标准,但这是荒谬的。

标签: c language-lawyer c11 c17


【解决方案1】:

6.2.6.2 Integer Types 首先为 unsigned 子类型定义 valuepadding 位(unsigned char 除外)。

除了根本不必有任何填充位之外,没有说太多填充位。但可能不止一个,这与有符号类型的符号位不同。


对于过度填充 short 直到它比 long 长,没有常识规则,无论 long 是否具有更多值位。


(值)位数与最大值之间的直接隐含关系也显示在标题5.2.4.2.1 Sizes of integer types <limits.h> 中。这定义了最小最大 ,而不是对象 sizes(CHAR_BIT 除外)。

其余的取决于名称本身和实现的手中:shortlong,而不是 smalllarge。说“我是一个节省空间的整数”比说“我是一个最大值减小的整数”更好。

【讨论】:

    【解决方案2】:

    非常感谢所有参与寻找答案的人。 大多数回复都分享了我已经学到的东西,但一些 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 应用于类型为charunsigned charsigned 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 的陈述给人的印象是多个值(例如523-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_MINSHRT_MAX),即至少 2 个字节 (如果字节是 8 位,请参见上面的“字节中的位数”)。
    unsigned short int至少 16 个值位(上面的USHRT_MAX),即至少 2 个字节

    继续该逻辑(参见 5.2.4.2.1/1):
    int 具有至少 15 个值位(参见 INT_MININT_MAX),即 至少 2 个字节
    unsigned int 具有至少 16 个值位(参见 UINT_MAX),即至少 2 个字节long int 具有至少 31 个值位(参见 LONG_MINLONG_MAX),即至少 4 个字节
    unsigned long int 具有 至少 32 个值位(参见 ULONG_MAX),即至少 4 个字节
    long long int 具有至少 63 个值位 (参见LLONG_MINLLONG_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_MININT_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)

    【讨论】:

    • 转化排名决定了大小。当然,没有什么能阻止功能失调的编译器让我们说短 100 字节大,但只使用其中的 2 个。但为什么有人会为了它而这样做呢?为什么范围不对应于字节大小? C 标准中没有要求编译器供应商必须使用常识,但正因为如此,我们不能假设编译器的设计没有常识。
    • @Lundin, > “转化排名决定尺寸”。您能否请我参考标准中确认这一点的特定部分?
    • 我已经在回答中这样做了。 “具有较小整数转换等级的类型的值范围是其他类型值的子范围”。因此,例如short 的值是int 值的子范围。这并不能阻止实现使短 666 字节变大但只使用 2,但是你为什么要这样做呢?我们必须假设编译器实现者能够使用常识。关于填充位的讨论也大多是无意义的,因为所有理智的现代系统都使用 2 的补码。
    【解决方案3】:

    来自 ISO/IEC 9899:2017 的初步审查(您的 C17 C17_N2176 链接):

    1. “5.2.4.2.1 整数类型的大小<limits.h>”部分的范围为(+ 或 -)(2 提升为 n)-1 信息(表示该类型的位数)。
    2. “6.2.5 类型”部分第 5 点说“...“普通” int 对象具有执行架构所建议的自然大小 环境(足够大以包含 INT_MIN 到 INT_MAX 范围内的任何值,如 标头<limits.h>)。'

    这让我觉得范围指定了类型可以是最小的位大小。可能有些架构分配的尺寸大于这个最小尺寸。

    【讨论】:

      【解决方案4】:

      相关部分是:

      环境限制和limits.h,来自 C17 5.2.4.2.1“整数类型 的大小”。如果我们只看无符号类型,那么实现至少需要支持的最小值是:

      UCHAR_MAX 255
      USHRT_MAX 65535
      UINT_MAX 65535
      ULONG_MAX 4294967295
      ULLONG_MAX 18446744073709551615
      

      然后检查 C17 6.3.1.1 部分关于整数转换等级(另见Implicit type promotion rules):

      • 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)
      

      【讨论】:

      • 这个问题询问的是尺寸,这个答案中没有任何东西可以证明尺寸之间的任何关系。 unsigned short 可以有 16 个值位和 48 个填充位,而unsigned int 有 32 个值位并且没有填充位。这满足等级和范围要求,但不会产生 sizeof (unsigned short)sizeof (unsigned int)。此外,问题要求提供证据。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-05
      • 1970-01-01
      • 2016-10-03
      • 2018-01-21
      • 2010-10-16
      相关资源
      最近更新 更多