C语言中比较指向不同char对象的两个指针是否为未定义行为?
memmove实现中的指针比较是否属于未定义行为?
以下是gcc中memmove的实现代码:
void * memmove (void *dest, const void *src, size_t len) { char *d = dest; const char *s = src; if (d < s) while (len--) *d++ = *s++; else { char *lasts = s + (len-1); char *lastd = d + (len-1); while (len--) *lastd-- = *lasts--; } return dest; }
C11标准在6.5.8. 关系运算符中规定:
当比较两个指针时,结果取决于所指向对象在地址空间中的相对位置。若两个指向对象类型的指针指向同一个对象,或都指向同一个数组对象的最后一个元素之后的位置,则它们相等。若所指向的对象是同一个聚合对象的成员,则指向结构体中后声明成员的指针大于先声明成员的指针,指向数组中下标值较大元素的指针大于下标值较小元素的指针。指向同一个联合对象所有成员的指针都相等。若表达式P指向数组对象的一个元素,表达式Q指向同一个数组对象的最后一个元素,则指针表达式Q+1大于P。除此之外的所有情况,行为都是未定义的。
上述代码中存在比较两个不同对象指针的操作:
if (d < s)
这是否属于未定义行为?或者说,指向char类型的指针比较是良定义的?
解答
严格按照C11标准的定义,这个d < s的比较属于未定义行为——当两个char*指针指向完全无关的对象(既不属于同一聚合体、同一数组,也不是同一数组的末尾位置)时,关系运算符的比较结果是标准未规定的。
但在实践中,主流平台和编译器会让这个操作正常工作:
- 主流硬件的地址空间是线性统一的,
char*指针本质对应线性地址的数值,比较指针大小等价于比较地址数值,平台层面有明确的结果。 memmove作为标准库核心函数,编译器会针对这类代码做特殊兼容处理,保证其行为符合预期。
需要注意的是:这种“依赖平台行为”的写法只适合标准库这类特殊场景,普通应用代码绝对不要依赖指针跨对象的关系比较,必须严格遵循C标准的规定,只在指针指向同一对象、同一数组或聚合体成员时使用关系比较。
内容的提问来源于stack exchange,提问作者k1r1t0
相关产品推荐
相关产品推荐

