此代码片段打印该值5
。我不明白为什么。
#include <stdio.h>
struct A
{
int x;
};
struct B
{
struct A a;
int y;
};
void printA(struct A *a)
{
printf("A obj: %d\n", a->x);
}
int main(void)
{
struct B b = {
{
5
},
10
};
struct A *a = (struct A*)&b;
printA(a);
printf("Done.\n");
return 0;
}
当我创建时b
,指向它的指针将指向数据{ {5}, 10 }
.
当我施放时&b
to struct A*
,我向编译器保证这struct A*
指向数据类型的单个数据元素的结构int
。相反,我向它提供一个指向两个数据类型数据元素的结构的指针struct A
, int
.
即使第二个变量被忽略(因为struct A
只有一个数据成员)我仍然为其提供一个结构,其成员为数据类型struct A
, not int
.
因此,当我通过a
to printA
, 线a->x
执行,本质上是要求访问第一个数据元素a
。第一个数据元素a
是数据类型struct A
,这是由于类型不匹配%d
期待一个数字,而不是一个struct A
.
这里究竟发生了什么?
语言律师对代码为何良好的解释:
- C 中的任何指针都可以转换为任何其他指针类型。 (C17 6.3.2 §7)。
- 转换后取消引用所指向的对象是否安全取决于:1) 类型是否兼容并因此正确对齐,以及 2) 所使用的相应指针类型是否允许别名。
-
作为一种特殊情况,指向结构类型的指针相当于指向其第一个成员的指针。 C17 6.7.2 §15 的相关部分说:
指向结构体对象的指针,
适当转换后,指向其初始成员(或者如果该成员是位字段,则指向中的单位
它所在的位置),反之亦然。
这意味着(struct A*)&b
很好。&b
被适当地转换为正确的类型。
-
不存在违反“严格别名”的情况,因为我们满足 C17 6.5 §7:
对象的存储值只能由具有以下类型之一的左值表达式访问:
- 与对象的有效类型兼容的类型,
...
- 其成员中包含上述类型之一的聚合或联合类型
初始成员的有效类型是struct A
。打印函数内部发生的左值访问没问题。struct B
也是一个聚合类型,包括struct A
在其成员之间,因此无论顶部引用的初始成员规则如何,严格的别名违规都是不可能的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)