【问题标题】:Why is register array indexing undefined?为什么寄存器数组索引未定义?
【发布时间】:2015-08-31 13:40:43
【问题描述】:

查看 C11 6.3.2.1 第 3 段:

除非它是sizeof 运算符、_Alignof 运算符或一元& 运算符的操作数,或者是用于初始化数组的字符串字面量,否则表达式的类型为“array of type”被转换为类型为“pointer to type”的表达式,它指向数组对象的初始元素,而不是左值。如果数组对象有register存储类,则行为未定义。

对于这种情况,

未定义 行为似乎是一个奇怪的选择。未定义的行为“没有要求”(3.4.3)。换句话说,仅根据 6.3.2.1 的措辞,对使用 register 声明的数组进行索引(或做一些其他事情)大概是允许编译、运行和执行代码看起来没有的事情发出错误。

register int a[5];
a[0] = 6; // apparently not required to cause an error?

这似乎与关键字的精神相矛盾,关键字的精神(根据 6.5.3.2)防止左值的地址被 & 占用。这并不完全相同,但肯定是相关的,因为隐式数组->指针转换和左值上的& 生成相同类型的结果:指向对象存储的指针。

6.7.1 的脚注明确说明了这种关系:

使用存储类说明符 register 声明的对象的任何部分的地址都无法显式计算(通过使用 6.5.3.2 中讨论的一元 & 运算符)或隐式计算(通过转换数组指向 6.3.2.1 中讨论的指针的名称)。

所以如果它“不能”完成,为什么转换un定义而不是错误的,或者(对于索引,还有一些其他选项)实现定义? p>

它不像 6.3.2.1 中的疏忽,因为根据其他提及,register 的含义很简单;如果那句话没有另外说明,我认为它是完全明确的。有什么值得怀疑的?

【问题讨论】:

  • Is it possible to keep an entire array in cpu register相关,最近看到这个问题,但不记得为什么了。
  • 我想知道是否打算允许扩展,但不对它们的确切含义施加任何要求?在很多情况下,C 没有一个术语,其含义不如实现定义的(需要实现来指定某些东西)或未指定的(需要从一组固定的选项中选择),但不像未定义(什么都行)。就个人而言,我认为 register 可能是一个有用的关键字,如果一个函数采用 register int* 类型的参数承诺不保留指针,因此此类函数的调用者......
  • ...可以保留地址传递给该函数的变量(但通常不公开)可以在调用其他函数时将这些变量缓存在寄存器中(这可能,但对于 register 关键字,能够访问早期函数调用保留的指针)。

标签: c language-lawyer undefined-behavior


【解决方案1】:

请记住,未定义行为允许一切,包括“以特定平台上预期的方式行事”。 IE。对于具有硬件数组寄存器的平台,您希望它能够编译,对于一个您不希望它编译的平台。将其保留为 UB 允许两者。

IIRC a 6502 在地址空间的开头有 256 个内存映射寄存器。

【讨论】:

  • 大多数 6502 指令都有一个寻址模式,假设地址的高字节为零,例如“lda 57”只占用两个字节而不是三个字节。此外,还有间接寻址模式,可以从前 256 个中的任意两个连续内存位置获取两个字节,并将它们的值用作地址的低字节和高字节。虽然这意味着零页地址可以用于类似于其他机器上的地址寄存器的目的,但对这些地址的访问就像其他任何机器一样进入外部存储器总线。在...中找到的 6510...
  • ...Commodore 64 添加了一个 I/O 端口,其中一个数据方向寄存器在地址 $0000 和一个数据寄存器在地址 $0001;我认为这个想法是允许将 64K 的地址空间完全存储为 RAM,而不需要为控制内存映射的 I/O 设备保留一组地址,而是将通用 I/O 端口放置到 CPU似乎是一种奇怪的方法。
猜你喜欢
  • 2012-06-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-20
  • 2012-12-08
  • 1970-01-01
  • 2015-03-23
  • 2012-02-05
  • 2016-01-28
相关资源
最近更新 更多