我有一个看起来像这样的结构:
struct packet {
int a;
char data[500];
};
typedef struct packet packet_t;
我有点困惑为什么以下代码为每个printf输出相同的地址:
void myfunction() {
packet_t packet;
printf("%p\n", packet.data); //e.g., outputs 0x7fff1c323c9c
printf("%p\n", &packet.data); //e.g., outputs 0x7fff1c323c9c
}
有没有人对此有好的解释?
答案 0 :(得分:7)
在大多数情况下,类型为“N-element array of T
”的表达式将转换为“指向T
的指针”类型的表达式,其值将是数组中的第一个元素。这是第一个printf
电话中发生的情况;类型为packet.data
的表达式char [500]
将替换为char *
类型的表达式,其值为第一个元素的地址,因此您可以有效地打印{{1 }}。
当数组表达式是一元&packet.data[0]
运算符的操作数时,会发生此规则的一个例外;表达式&
的类型是&packet.data
(指向char (*)[500]
的500个元素数组的指针)。
数组的地址与第一个元素的地址相同,因此对char
的两次调用都显示相同的值;只是表达式的类型不同。为了迂腐,两个表达式都应该转换为printf
调用中的void *
(printf
转换说明符需要%p
参数):
void *
答案 1 :(得分:4)
那是因为数组衰减到指向序列中第一个元素的指针。因此,packet.data
地址位置与&packet.data
或&packet.data[0]
相同。
答案 2 :(得分:1)
我不知道为什么这会被拒绝,这是一个很好的问题,暴露了C的混乱行为。
混淆是因为通常在定义数组时会创建一个真实的指针:
char data[100];
printf("%p\n", data); // print a pointer to the first element of data[]
printf("%p\n", &data); // print a pointer to a pointer to the first element of data[]
因此,在典型的32位桌面系统上,为data
分配了4个字节,这是指向100个字符的指针。 Data
,指针本身存在于内存中。
在struct中创建数组时,不会分配指针。相反,编译器会在运行时将对packet.data
的引用转换为指针,但不会分配任何内存来存储它。相反,它只使用&packet + offsetof(data)
。
就个人而言,我更希望语法保持一致并需要一个&符号,而packet.data会产生某种编译时错误。
答案 3 :(得分:0)
根据 C11 (6.3.2.1.3) 部分。
当数组用作 sizeof
和一元 &
运算符的操作数时,数组会衰减为指向其第一个元素的指针。
因此 packet.data
不会在表达式 &packet.data[0]
中衰减为 &packet.data
。结果将是一个 char (*)[500]
类型的指针,并且在数字上与其第一个元素的地址 packet.data[0]
相同。
答案 4 :(得分:-2)
因为除了使& packet.data导致编译错误之外,这是唯一合理的做法。整数a和数据字符数组按顺序排列在堆栈中,不涉及解除引用。