Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么寄存器数组索引未定义?_C_Language Lawyer_Undefined Behavior - Fatal编程技术网

C 为什么寄存器数组索引未定义?

C 为什么寄存器数组索引未定义?,c,language-lawyer,undefined-behavior,C,Language Lawyer,Undefined Behavior,查看C11 6.3.2.1第3段: 除非它是sizeof运算符的操作数、\u Alignof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则类型为“array of type”的表达式将转换为类型为“pointer to type”的表达式它指向数组对象的初始元素,不是左值。如果数组对象具有寄存器存储类,则行为未定义 在这种情况下,未定义的行为似乎是一个奇怪的选择。未定义的行为“不施加任何要求”(3.4.3)。换言之,仅根据6.3.2.1的措辞,对使用register声明的数

查看C11 6.3.2.1第3段:

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

在这种情况下,未定义的行为似乎是一个奇怪的选择。未定义的行为“不施加任何要求”(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的脚注明确了这种关系:

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

因此,如果它“不能”完成,为什么转换是未定义的,而不是错误的,或者(对于索引,在有一些其他选项的情况下)定义了实现


它不像6.3.2.1中的疏忽,因为根据其他提到的内容,
register
的意思足够简单;如果那句话没有说其他的话,我会认为这句话是非常明确的。有什么值得怀疑的?

记住,未定义的行为允许一切,包括“以特定平台上预期的方式进行行为”。也就是说,对于一个有硬件阵列寄存器的平台,您希望对其进行编译;对于一个没有硬件阵列寄存器的平台,您不希望对其进行编译。离开它,两者都可以


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

与之相关,我最近看到了这个问题,尽管我不记得为什么。我想知道其目的是否是允许扩展,但不对其确切含义提出任何要求?在许多情况下,C的术语的含义没有实现定义(需要实现指定某些内容)或未指定(需要从一组固定的选项中进行选择)那么严格,但没有定义得那么松散(任何内容都可以)。就我个人而言,如果一个函数使用了
register int*
类型的参数,并承诺不持久化指针,那么
register
可能是一个有用的关键字,因此这样一个函数的调用者……可以保留其地址传递给该函数的变量(但通常不会公开)在调用其他函数时,可以将这些变量缓存在寄存器中(如果没有register关键字,可能会访问早期函数调用保留的指针)。大多数6502指令都有一种寻址模式,即假定地址的上字节为零,例如“lda 57”只需要两个字节,而不是三个字节。此外,还有间接寻址模式,可以从前256个内存位置中的任意两个连续内存位置获取两个字节,并将其值用作地址的低字节和高字节。虽然这意味着零页地址可以用于与其他机器上的地址寄存器类似的目的,但对这些地址的访问像其他任何机器一样进入外部内存总线。在……Commodore 64中发现的6510增加了一个I/O端口,在地址$0000处有一个数据方向寄存器,在地址$0001处有一个数据寄存器;我认为这个想法是允许64K的地址空间完全存储为RAM,而不需要为控制内存映射的I/O设备保留一组地址,但将通用I/O端口放在CPU上似乎是一种奇怪的方法。