arr
是一个指针,但从注释中我们可以假定它指向某个数组A
的元素0.
考虑一下表达式arr + size - 2
.arr + size
是没有争议的;它指向&A[1]
,即使A
是一个由1个元素组成的数组,因此&A[1]
是该数组最后一个元素"后面"的地址.
对于arr + size - 2
,实际上是&A[1] - 2
,我们认为C 2018 6.5.6 8:
如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向距原始元素的元素偏移量,以便结果数组元素和原始数组元素的下标差等于整数表达式.换言之,如果表达式P
指向数组对象的第i个元素,则表达式(P)+N
(等价地,第N+(P)
)和第(P)-N
(其中N
具有值n)分别指向数组对象的第i+n个和第i个−第n个元素,provided they exist[增加了强调]…
此段落不定义&A[1] - 2
的结果,因为索引为−1的数组A
的元素不存在.仅此一项就足以呈现未定义的行为,因为标准中没有其他内容对其进行定义,并且C 2018 4 2告诉我们:未定义的行为在本文档…中以其他方式指示因为省略了对行为的任何明确定义.但是,6.5.6 8继续:
…如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象最后一个元素之后的元素,则求值不会产生溢出;否则,行为为未定义的…
在这里,指针操作数(&A[1]
)和结果(&(A[-1]
)不指向同一数组对象的元素,也不指向它后面的一个数组对象的元素,因此行为未定义.
arr + size - 2
的求值发生在调用memmove
之前,因此memmove
是否使用其相应的参数是无关紧要的;行为已经未定义.