背景
我创建了一个基本的链表数据结构,主要是为了学习目的。这个链表的一个目标是它可以处理不同的数据结构。因此,我尝试使用结构体组合来模拟C语言中的“继承”。以下是构成我的链表基础的结构体。
typedef struct Link {
struct Link* next;
struct Link* prev;
} Link;
typedef Link List;
在我的实现中,我选择使用一个哨兵节点作为列表的头部和尾部(这就是 Link == List 的原因)。
为了使列表实际处理数据,一个结构体只需要将 Link 结构体作为第一个成员即可:
typedef struct {
Link link;
float data;
} Node;
于是链接列表看起来像这样。
┌───┬───┬───┐ ┌───┬───┐ ┌───┬───┬───┐
... <--->│ P │ N │ D │<--->│ P │ N │<--->│ P │ N │ D │<---> ...
└───┴───┴───┘ └───┴───┘ └───┴───┴───┘
End Node myList First Node
List myList;
Node node1 = {{}, 1.024};
....
Node nodeN = {{}, 3.14};
list_init(&myList) // myList.next = &myList; myList.prev = &myList;
list_append(&myList, &node1);
....
list_append(&myList, &nodeN);
问题
为了遍历这个列表,一个 Node
指针最初指向 第一个节点。然后沿着列表遍历,直到它再次指向哨兵节点时停止。
void traverse()
{
Node* ptr;
for(ptr = myList.next; ptr != &myList; ptr = ptr->link.next)
{
printf("%f ", ptr->data);
}
}
我的问题与这行代码ptr != &myList
有关。这行代码是否存在指针对齐问题?
for循环正确地产生了警告:(warning: assignment from incompatible pointer type
和warning: comparison of distinct pointer types lacks a cast
),可以按照警告信息所示进行强制类型转换为Node*
,从而消除警告。然而,这是一个愚蠢的行为吗?当指针指向&myList
时,我永远不会访问ptr->data
,因为循环一旦满足ptr == &myList
就会终止。
TLDR
在C语言中的结构体中,如果Derived
是以Base
作为第一个成员,则Base*
可以指向Derived
。如果没有访问到Derived
特定的成员,那么Derived*
可以指向Base
吗?
编辑:用等价的内联代码替换了相关函数调用。
List
作为Node
的别名,并忽略List
的data
成员?或者直接将其定义为Node
(而不是List myList;
,而是Node myList;
)这将是一个更干净的方法来避免指针转换的问题。我同意其他评论中所说的:清晰地陈述了问题。 (+1) - lurkerptr != &myList
的目的是什么;它在标准C中是不允许的,gcc则会发出警告。例如,这是否意味着(List *)ptr != &myList
或ptr != (Node *)&myList
?我建议第一个是可以的,但第二个理论上可能会违反对齐约束,就像ptr = ptr->link.next
(应该是ptr = (Node *) ptr->link.next
) 一样。 - davmacBase*
指针是一个Derived*
指针,反之亦然,这不违反严格别名规则吗? - Cyan