【问题标题】:Is Byte Really The Minimum Addressable Unit?字节真的是最小可寻址单位吗?
【发布时间】:2020-02-15 17:55:29
【问题描述】:

C11 标准的第 3.6 节将“字节”定义为“数据存储的可寻址单元……保存……字符”。

C++11 标准第 1.7 节将“字节”定义为“C++ 内存模型中的基本存储单元……包含……字符”。

两个定义都没有说“字节”是最小的可寻址单位。这是因为标准有意从特定机器中抽象出来吗?您能否提供一个真实的机器示例,其中 C/C++ 编译器决定“字节”比最小可寻址单元长/短?

【问题讨论】:

  • 我最喜欢的不同寻常的架构之一是HP Saturn。它是一个 4 位 CPU,机器可以寻址半字节。有a gcc port,其中char 是8 位。这就是你要找的东西吗?
  • 我认为你不应该修改你的报价。 relevant C++11 section 说:“C++ 内存模型中的基本存储单元是字节。”这是一个完整的句子,没有限定。然后它添加“一个字节至少足够大以包含基本执行字符集的任何成员和[...]”。并在其后加上“每个字节都有一个唯一的地址。”。
  • 嗯,sizeof(char)定义为1,char指针递增1,ptrdiff_t是整数类型。这意味着对于常规 C/C++ 指针,字符是内存的“单元”,是最小的可寻址实体。
  • @RaymondChen 不必这样做:它可以简单地将 CHAR_BIT 定义为单词的大小。
  • @Ruslan 然而在 18/36 位字寻址系统上有相当多的 9 位字符的历史......

标签: c++ c language-lawyer standards memory-model


【解决方案1】:

字节是严格符合 C 代码的最小可寻址单元。 C实现执行程序的机器是否支持寻址较小的单元与此无关; C 实现必须提供一个视图,其中字节是严格符合 C 代码中的最小可寻址单元。

C 实现可以支持将更小的单元作为扩展来寻址,例如简单地定义某些 C 标准未定义的指针操作的结果。

【讨论】:

  • 对语言律师标记问题的回答应参考规范,不是吗?
  • @LanguageLawyer:历史显示该标签最初不是在问题上,而是在提交此答案三分钟后添加(而不是由 OP)。我以后可能会更新。或者我们可以通过删除标签来修复它,因为以使现有答案无效的方式更改问题是不合适的。
  • 历史显示标签最初不是在问题上好的,那么抱歉。
  • @LanguageLawyer:我看了一点,我认为这里没有太多引用标准的要求。 C 2018 6.2.6.1 2 告诉我们,所有对象都由字节组成,除了位字段,我们后来被告知将其放入未定义的“存储单元”中。但这是众所周知的,其他对字节和寻址的引用散布在标准中,也是众所周知的。标准中的任何内容都没有给出子字节寻址的提示,因此对它的任何支持都将是实现扩展,证明我的说法是严格意义上的字节是最小的可寻址单元......
  • … 符合代码。作为一名数学家,我有时会欣赏一个真正正式的证明,所以如果 OP 有要求,我可能会倾向于写更多的东西。但是由于第三方后来添加了语言律师标签,我暂时不理会它。
【解决方案2】:

8051 系列是最小可寻址单元小于一个字节的真实机器及其编译器的一个示例。我习惯的一种编译器是 Keil C51。

最小的可寻址单元是位。你可以定义一个这种类型的变量,你可以读写它。但是,定义变量的语法是非标准的。当然,C51 需要几个扩展来支持所有这些。顺便说一句,不允许指向位的指针。

例如:

unsigned char bdata bitsAdressable;
sbit bitAddressed = bitsAdressable^5;

void f(void) {
    bitAddressed = 1;
}

bit singleBit;

void g(bit value) {
    singleBit = value;
}

【讨论】:

  • 从阅读 Wikipedia 文章看来,它的内存只有一部分是位可寻址的,我认为这就是为什么你需要一个不同的类型来使用它?
  • 需要sbit 类型才能允许特殊定义。实际上,您可以直接定义一个位变量,正如我在编辑后的答案中显示的那样。链接器将此变量放在内部 RAM 的可位寻址部分。但是,需要的类型是bit,这也是不同的。
【解决方案3】:

两个定义都没有说“字节”是最小可寻址单位。

那是因为他们不需要。字节类型(charunsigned charstd::byte 等)有足够的限制来强制执行此要求。

字节类型的大小为explicitly defined to be precisely 1:

sizeof(char)、sizeof(signed char) 和 sizeof(unsigned char) 为 1。

字节类型的对齐is the smallest alignment possible:

此外,窄字符类型 (6.9.1) 应具有最弱的对齐要求

当然,这不一定是 1 的对齐方式。除了...确实如此。

看,如果对齐高于 1,这意味着简单的字节数组将不起作用。数组索引是基于指针运算,指针运算根据sizeof(T)确定下一个地址。但是如果alignof(T) 大于sizeof(T),那么T 的任何数组中的第二个元素都会错位。这是不允许的。

因此,即使标准没有明确规定字节类型的对齐方式为 1,但其他要求确保它必须是。

总的来说,这意味着每个指向对象的指针都具有至少与字节类型一样严格的对齐方式。因此,相对于按字节类型的对齐方式,没有对象指针可以错位。因此,所有有效的非 NULL 指针(指向活动对象或过去的指针)必须至少对齐到足以指向 char

同样,两个指针之间的差异是defined in C++,作为这些指针指向的元素的数组索引之间的差异(C++ 中的指针算法要求两个指针指向同一个数组)。加法指针算法如前所述,基于指向的类型sizeof

鉴于所有这些事实,即使实现的指针的地址可以寻址小于char 的值,C++ 抽象模型在功能上不可能生成一个指针并仍然拥有它指针计数为有效(指向对象/函数、数组的末尾或为 NULL)。您可以使用整数转换来创建这样的指针值。但是你会创建一个无效的指针值。

因此,虽然从技术上讲,机器上可能存在较小的地址,但您永远无法在有效、格式良好的 C++ 程序中实际使用它们。

显然编译器扩展可以做任何事情。但就符合标准的程序而言,根本不可能生成针对字节类型未对齐的有效指针。

【讨论】:

    【解决方案4】:

    我早在 1990 年代初就对 TMS34010 及其后继 TMS34020 图形芯片进行了编程,它们有一个平坦的地址空间,并且是可寻址的,即每个位都有索引的地址。这对于当时和过去内存非常宝贵的计算机图形非常有用。

    embedded C-compiler 并没有真正需要直接访问单个位,因为从(标准)C 语言的角度来看,字节仍然是前一篇文章中指出的最小单位。

    因此,如果您想在 C 中读取/写入位流,则需要一次读取/写入(至少)一个字节并缓冲(例如在编写算术或 Huffman 编码器时)。

    【讨论】:

      【解决方案5】:

      (谢谢大家的评论和回答,每一句话都有帮助)

      编程语言的内存模型和目标机器的内存模型是不同的东西。

      是的,字节是编程语言内存模型上下文中的最小可寻址单元。

      不,字节不是机器内存模型上下文中的最小可寻址单元。例如,有些机器的最小可寻址单元比编程语言的“字节”长或短:

      • 更长:HP Saturn - 4 位单元与 8 位字节 gcc(感谢 Nate)。
      • 更短:IBM 360 - 36 位单元与 6 位字节(感谢 Antti)
      • 更长:Intel 8051 - 1 位单元与 8 位字节(感谢 Busybee)
      • 更长:Ti TMS34010 - 1 位单元与 8 位字节(感谢 Wcochran)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-08-28
        • 1970-01-01
        • 2011-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多