aaf*_*lei 9 c pointer-arithmetic language-lawyer
据说在 C 中,当指针指向同一个数组或该数组末尾之后的一个元素时,算术和比较是明确定义的。那么数组第一个元素之前的一个呢?只要我不取消引用就可以了吗?
给定的
int a[10], *p;
p = a;
Run Code Online (Sandbox Code Playgroud)
(1) 写字合法--p吗?
(2)p-1在表达式中写入是否合法?
(3) 如果 (2) 没问题,我可以断言p-1 < a吗?
对此有一些实际的担忧。考虑一个reverse()函数,它反转以 结尾的 C 字符串'\0'。
#include <stdio.h>
void reverse(char *p)
{
char *b, t;
b = p;
while (*p != '\0')
p++;
if (p == b) /* Do I really need */
return; /* these two lines? */
for (p--; b < p; b++, p--)
t = *b, *b = *p, *p = t;
}
int main(void)
{
char a[] = "Hello";
reverse(a);
printf("%s\n", a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我真的需要检查代码吗?
请从语言律师/实践的角度分享您的想法,以及您将如何应对此类情况。
(1)写--p合法吗?
它是“合法的”,因为在 C 语法中允许它,但它会调用未定义的行为。为了查找标准中的相关部分,--p等效于p = p - 1(除了p仅评估一次)。然后:
C17 6.5.6/8
如果指针操作数和结果都指向同一个数组对象的元素,或者数组对象的最后一个元素之后,求值不会产生溢出;否则,行为未定义。
该评估所调用未定义的行为,这意味着它并不重要,如果你去参考指针或不-你已经调用未定义的行为。
此外:
C17 6.5.6/9:
两个指针相减时,都指向同一个数组对象的元素,或者指向数组对象最后一个元素后的一个;
如果您的代码违反了 ISO 标准中的“应”,则会调用未定义的行为。
(2) 在表达式中写 p-1 是否合法?
与 (1) 相同,未定义的行为。
至于这在实践中如何导致问题的示例:想象一下数组被放置在一个有效内存页面的最开始。当您在该页面之外递减时,可能会出现硬件异常或指针陷阱表示。对于微控制器来说,这并不是完全不可能的情况,尤其是当它们使用分段存储器映射时。