C 中的指针与数组,非同小可的区别

2024-04-22

我以为我真的理解了这一点,重新阅读标准(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 指向数组的第一个成员?


如果我忽略了您分析中的任何内容,请原谅我。但我认为这一切的根本错误是这个错误的假设

type2_p->ptr 的类型为“指向 int 的指针”,其值为 my_test 的起始地址。

没有什么可以使它具有这样的价值。相反,它很可能指向某个地方

0x00000001

因为您所做的是将组成该整数数组的字节解释为指针。然后向其中添加一些内容和下标。

另外,我非常怀疑您对其他结构的转换实际上是有效的(例如,保证有效)。如果两个结构都是联合的成员,则可以强制转换然后读取任一结构的公共初始序列。但它们不在你的例子中。您还可以转换为指向第一个成员的指针。例如:

typedef struct {
    int array[3];
} type1_t;

type1_t f = { { 1, 2, 3 } };

int main(void) {
    int (*arrayp)[3] = (int(*)[3])&f;
    (*arrayp)[0] = 3;
    assert(f.array[0] == 3);
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 中的指针与数组,非同小可的区别 的相关文章

随机推荐