结构成员之间的指针差异?

Bla*_*iev 7 c pointers c99 ptrdiff-t

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);
Run Code Online (Sandbox Code Playgroud)

这显然打破了上述规则,因为pq指针指向不同的"数组对象",并且根据规则,q - p差异是未定义的.

但在实践中,为什么这样的事情会导致未定义的行为?毕竟,struct成员按顺序排列(就像数组元素一样),成员之间有任何潜在的填充.确实,填充量会因实现而异,这会影响计算结果,但为什么结果应该是"未定义"?

我的问题是,我们可以假设标准只是对这个问题"无知",还是有充分的理由不扩大这个规则?难道不能将上述规则改为" 两者都应指向同一数组对象的元素或同一结构的成员 "吗?

我唯一怀疑的是分段内存架构,其中成员可能最终分成不同的段.是这样的吗?

我也怀疑这就是为什么GCC定义它自己的原因__builtin_offsetof,以便有一个"符合标准"的offsetof宏定义.

编辑:

正如已经指出的那样,标准不允许对void指针进行算术运算.它是一个GNU扩展,仅在GCC通过时才会触发警告-std=c99 -pedantic.我用void *指针替换char *指针.

Kei*_*son 3

char*同一结构的成员地址之间的减法和关系运算符(类型上)定义良好。

\n\n

任何对象都可以被视为数组unsigned char

\n\n

引用N1570 6.2.6.1 第 4 段:

\n\n
\n

存储在任何其他对象类型的非位字段对象中的值由n \xc3\x97CHAR_BIT位组成,其中 n 是该类型的对象的大小(以字节为单位)。该值可以被复制到\n n类型的对象中 (例如,通过);得到的字节集被称为值的对象表示。unsigned char [ ]memcpy

\n
\n\n

...

\n\n
\n

我唯一的怀疑是分段内存架构,其中成员可能最终位于不同的段中。是这样吗?

\n
\n\n

不可以。对于具有分段内存体系结构的系统,通常编译器会施加限制,即每个对象必须适合单个段。或者它可以允许对象占用多个段,但它仍然必须确保指针算术和比较正确工作。

\n

  • 我不相信。如果指向对象的指针始终可以被视为指向最外层封闭对象的指针,例如 struct hack 也是合法的...... (2认同)