我正在尝试调整以下版本的 stpcpy
函数,以在内部使用 restrict
限定指针作为其参数,但我不确定是否只是简单添加限定符会导致引入未定义的行为。
#define ALIGN (sizeof(size_t)-1)
#define ONES ((size_t)-1/UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX/2+1))
#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS)
char *__stpcpy(char *d, const char *s)
{
size_t *wd;
const size_t *ws;
if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) {
for (; (*d=*s) && ((uintptr_t)s & ALIGN); s++, d++);
if (!*s) return d;
wd=(void *)d; ws=(const void *)s;
for (; !HASZERO(*ws); *wd++ = *ws++);
d=(void *)wd; s=(const void *)ws;
}
for (; (*d=*s); s++, d++);
return d;
}
假设 C99 6.7.3.1 中有关访问对象的规则仅适用于访问的单个对象而不是整个数组,我认为这可能没问题,因为写入的元素仅访问一次,并且仅用于写入。但此时我对使用 restrict
感到相当不舒服,并且不想仅依赖我自己的判断。
最佳答案
为了符合标准,唯一的限制是操作函数通过 restrict
指针接收到的任何对象的所有指针表达式都应该基于该指针。它不要求指针表达式具有相同的类型。因此,从这个意义上说,通过这些 size_t*
访问对象并不是约束违规或 UB。
我不确定用 *d
读取您通过 *wd
修改的对象的一部分的值是否会读取没有别名,因为指针类型不同。但正如你所说,你不会这样做,所以这应该是安全的。
顺便说一句,代码做了一个不一定可移植的重要假设,即 uintptr_t 的低位反射(reflect)了转换为它的指针的对齐属性。这对于我们日常使用中遇到的所有架构来说可能都是如此,但标准并不能保证。即使 C11 也只说了一些关于“字节地址的倍数”的内容,但没有任何内容指定它是什么。
关于令人困惑的调整代码以使用限制限定符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12255710/