C99 标准规定:
当两个指针相减时,都应指向同一个数组对象的元素,或者指向数组对象的最后一个元素
考虑以下代码:
struct test {
int x[5];
char something;
short y[5];
};
...
struct test s = { ... };
char *p = (char *) s.x;
char *q = (char *) s.y;
printf("%td\n", q - p);
这显然违反了上述规则,因为p
andq
指针指向不同的“数组对象”,并且根据规则,q - p
差异是未定义的。
但在实践中,为什么这样的事情会导致未定义的行为?毕竟,结构成员是按顺序排列的(就像数组元素一样),成员之间有任何潜在的填充。诚然,填充量会因实现而异,这会影响计算的结果,但为什么该结果应该是“未定义的”?
我的问题是,我们可以假设标准只是“无知”这个问题,还是有充分的理由不扩大这条规则?上述规则不能改写为“两者都应指向同一数组对象的元素或同一结构的成员”吗?
我唯一的怀疑是分段内存架构,其中成员可能最终位于不同的段中。是这样吗?
我也怀疑这就是 GCC 定义自己的原因__builtin_offsetof
,以便对offsetof
宏进行“符合标准”的定义。
编辑:
正如已经指出的那样,标准不允许对 void 指针进行算术运算。它是一个 GNU 扩展,仅在通过 GCC 时才会发出警告-std=c99 -pedantic
。我正在用void *
指针替换char *
指针。