我以为我真的理解了这一点,重新阅读标准(ISO 9899:1990)只是证实了我明显错误的理解,所以现在我在这里问。
以下程序崩溃:
#include <stdio.h>
#include <stddef.h>
typedef struct {
int array[3];
} type1_t;
typedef struct {
int *ptr;
} type2_t;
type1_t my_test = { {1, 2, 3} };
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
type1_t *type1_p = &my_test;
type2_t *type2_p = (type2_t *) &my_test;
printf("offsetof(type1_t, array) = %lu\n", offsetof(type1_t, array)); // 0
printf("my_test.array[0] = %d\n", my_test.array[0]);
printf("type1_p->array[0] = %d\n", type1_p->array[0]);
printf("type2_p->ptr[0] = %d\n", type2_p->ptr[0]); // this line crashes
return 0;
}
比较表达式my_test.array[0]
and type2_p->ptr[0]
根据我对标准的解释:
6.3.2.1 数组下标
"下标的定义
运算符 [] 是 E1[E2] 是
与 (*((E1)+(E2))) 相同。”
应用此给出:
my_test.array[0]
(*((E1)+(E2)))
(*((my_test.array)+(0)))
(*(my_test.array+0))
(*(my_test.array))
(*my_test.array)
*my_test.array
type2_p->ptr[0]
*((E1)+(E2)))
(*((type2_p->ptr)+(0)))
(*(type2_p->ptr+0))
(*(type2_p->ptr))
(*type2_p->ptr)
*type2_p->ptr
type2_p->ptr
具有“指向 int 的指针”类型,并且该值是起始地址my_test
. *type2_p->ptr
因此计算结果为一个整数对象,其存储位置与my_test
has.
Further:
6.2.2.1 左值、数组和函数指示符
“除非它是
sizeof 运算符或一元 &
运算符,...,一个左值
类型array of type
被转换为
有类型的表达式pointer to
type
指向初始的
数组对象的元素,并且不是
左值。”
my_test.array
具有“int 数组”类型,并且如上所述转换为“指向 int 的指针”,其中第一个元素的地址作为值。*my_test.array
因此计算结果为一个整数对象,其存储位置与数组中第一个元素的地址相同。
最后
6.5.2.1 结构和联合说明符
指向结构体对象的指针,
适当转换后,指向其
初始成员...,反之亦然。
内可能有未命名的填充
结构对象,但不是它的
开始,根据需要实现
适当的对齐。
自从第一个成员type1_t
是数组,起始地址
那个和整个type1_t
对象与上面描述的相同。
因此我的理解是*type2_p->ptr
评估为
一个整数,其存储位置与第一个整数的地址相同
数组中的元素,因此与*my_test.array
.
但事实并非如此,因为程序总是崩溃
在带有 gcc 版本 2.95.3、3.4.4 的 Solaris、cygwin 和 linux 上
和4.3.2,所以任何环境问题都是完全不可能的。
我的推理哪里错误/我不明白什么?
如何声明 type2_t 以使 ptr 指向数组的第一个成员?