【发布时间】: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