C中的指针与数组,非平凡的区别 [英] Pointer vs array in C, non-trivial difference

查看:27
本文介绍了C中的指针与数组,非平凡的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我以为我真的理解了这一点,重新阅读标准 (ISO 9899:1990) 只是证实了我明显错误的理解,所以现在我在这里问.

I thought I really understood this, and re-reading the standard (ISO 9899:1990) just confirms my obviously wrong understanding, so now I ask here.

以下程序崩溃:

#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]type2_p->ptr[0]:

Comparing the expressions my_test.array[0] and type2_p->ptr[0] according to my interpretation of the standard:

6.3.2.1 数组下标

6.3.2.1 Array subscripting

"下标的定义运算符 [] 是 E1[E2] 是等同于 (*((E1)+(E2)))."

"The definition of the subscript operator [] is that E1[E2] is identical to (*((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 的地址相同.

type2_p->ptr has type "pointer to int" and the value is the start address of my_test. *type2_p->ptr therefore evaluates to an integer object whose storage is at the same address that my_test has.

进一步:

6.2.2.1 左值、数组和函数指示符

6.2.2.1 Lvalues, arrays, and function designators

"除非它是操作数sizeof 运算符或一元 &运算符, ... , 一个左值,具有type array of type 转换为类型为 pointer to 的表达式类型 指向初始数组对象的元素,而不是一个左值."

"Except when it is the operand of the sizeof operator or the unary & operator, ... , an lvalue that has type array of type is converted to an expression with type pointer to type that points to the initial element of the array object and is not an lvalue."

my_test.array 具有int 数组"类型,并且如上所述转换为指向 int 的指针",并将第一个元素的地址作为值.*my_test.array 因此计算为一个整数对象,其存储地址与数组中的第一个元素的地址相同.

my_test.array has type "array of int" and is as described above converted to "pointer to int" with the address of the first element as value. *my_test.array therefore evaluates to an integer object whose storage is at the same address that the first element in the array.

最后

6.5.2.1 结构和联合说明符

6.5.2.1 Structure and union specifiers

指向结构对象的指针,适当转换,指向其初始成员...,反之亦然.内可能有未命名的填充结构对象,但不是在它的开始,必要时实现适当的对齐.

A pointer to a structure object, suitably converted, points to its initial member ..., and vice versa. There may be unnamed padding within a structure object, but not at its beginning, as necessary to achieve the appropriate alignment.

由于type1_t的第一个成员是数组,所以那和整个 type1_t 对象与上面描述的相同.因此,我的理解是 *type2_p->ptr 评估为一个整数,其存储地址与第一个地址相同数组中的元素,因此与 *my_test.array 相同.

Since the first member of type1_t is the array, the start address of that and the whole type1_t object is the same as described above. My understanding were therefore that *type2_p->ptr evaluates to an integer whose storage is at the same address that the first element in the array and thus is identical to *my_test.array.

但事实并非如此,因为程序一直崩溃在带有 gcc 版本 2.95.3、3.4.4 的 solaris、cygwin 和 linux 上和4.3.2,所以任何环境问题都完全不可能.

But this cannot be the case, because the program crashes consistently on solaris, cygwin and linux with gcc versions 2.95.3, 3.4.4 and 4.3.2, so any environmental issue is completely out of the question.

我的推理哪里错了/我不明白什么?如何声明 type2_t 使 ptr 指向数组的第一个成员?

Where is my reasoning wrong/what do I not understand? How do I declare type2_t to make ptr point to the first member of the array?

推荐答案

数组是一种存储.从语法上讲,它用作指针,但在物理上,该结构中没有指针"变量——只有三个整数.另一方面,int 指针是存储在结构体中的实际数据类型.因此,当您执行强制转换时,您可能*使 ptr 取数组中第一个元素的值,即 1.

An array is a kind of storage. Syntactically, it's used as a pointer, but physically, there's no "pointer" variable in that struct — just the three ints. On the other hand, the int pointer is an actual datatype stored in the struct. Therefore, when you perform the cast, you are probably* making ptr take on the value of the first element in the array, namely 1.

*我不确定这是否是实际定义的行为,但至少在大多数常见系统上是这样工作的.

*I'm not sure this is actually defined behavior, but that's how it will work on most common systems at least.

这篇关于C中的指针与数组,非平凡的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆