【发布时间】:2021-04-07 03:39:03
【问题描述】:
在某些示例中对 C 中琐碎的侵入式容器的实现感到困惑。 我有结构:
struct List {
struct Link* first;
struct Link* last;
};
Link for 成为列表的节点:
struct Link {
struct Link* pre;
struct Link* suc;
};
一些用于在列表中存储指定值的伪节点:
struct Name {
struct Link lnk;
char* n;
};
在List中推送值的功能:
void push_back(struct List* lst, struct Link* p) {
assert(lst);
{
struct Link* last = lst->last;
if (last) {
p->pre = last;
last->suc = p;
}
else {
lst->first = p;
p->pre = 0;
}
lst->last = p;
p->suc = 0;
}
}
List的用法和样例:
int main() {
int count = 0;
struct List names;
struct Link* curr;
init(&names);
push_back(&names, (struct Link*)make_name("Norah"));
push_back(&names, (struct Link*)make_name("Annemarie"));
push_back(&names, (struct Link*)make_name("Kris"));
curr = names.first;
for (; curr != 0; curr = curr->suc) {
count++;
printf("element %d: %s\n", count, ((struct Name*)curr)->n);
}
return 0;
}
问题是,在这个例子中类型转换是如何工作的?当sizeof(Link)==8 和sizeof(Name)==12
指针curr 指向为Name 类型分配的内存,该结构没有suc 和pre 成员,只有lnk 类型为Name 的对象(不是指针),并且在代码中没有任何主要访问权限为这个会员。
【问题讨论】:
-
结构体的地址等价于它的第一个成员的地址。因此,如果你有一个结构
Name,它总是有一个Link作为第一个成员,那么那个Name的地址也是那个Name的Link成员的地址,并且可以被利用因此。只是不要用它做指针算术。编译器可以在成员之间随意推动填充和对齐调整,但绝不会在 first 成员之前。