简体   繁体   English

C struct继承指针对齐

[英]C struct inheritance pointer alignment

Background背景

I have created a basic linked list data structure mainly for learning purposes.我创建了一个基本的链表数据结构,主要用于学习目的。 One goal of the list was that it can handle different data structures.该列表的一个目标是它可以处理不同的数据结构。 Therefore, I've tried my hand at structure composition to simulate "inheritance" in C. Here are the structures that form the basis for my linked list.因此,我尝试了结构组合以模拟 C 中的“继承”。以下是构成我的链表基础的结构。

typedef struct Link {
    struct Link* next;
    struct Link* prev;
} Link;

typedef Link List;

In my implementation I have chosen to have a sentinel node that serves as both the head and the tail of the list (which is why Link == List).在我的实现中,我选择了一个哨兵节点作为列表的头部和尾部(这就是 Link == List 的原因)。

To make the list actually handle data, a structure simply includes the Link structure as the first member:为了使列表真正处理数据,结构简单地包含链接结构作为第一个成员:

typedef struct {
    Link link;
    float data;
} Node;

So the linked list looks like this.所以链表看起来像这样。

         ┌───┬───┬───┐     ┌───┬───┐     ┌───┬───┬───┐     
... <--->│ 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);

Question

To traverse this list a Node pointer initially points to the First Node .为了遍历这个列表,一个Node指针最初指向First Node It then traverses along the list until it points to the sentinel again then stops.然后它沿着列表遍历,直到它再次指向哨兵,然后停止。

void traverse()
{
    Node* ptr;
    for(ptr = myList.next; ptr != &myList; ptr = ptr->link.next)
    {
        printf("%f ", ptr->data);
    }
}

My question is with the line ptr != &myList .我的问题是ptr != &myList Is there a pointer alignment problem with this line?这条线是否存在指针对齐问题?

The for loop correctly produces the warnings: ( warning: assignment from incompatible pointer type and warning: comparison of distinct pointer types lacks a cast ) which can be silenced by doing what it says and casting to Node* . for 循环正确产生警告:( warning: assignment from incompatible pointer typewarning: comparison of distinct pointer types lacks a cast强制转换)可以通过执行它所说的并将其强制转换为Node*来消除。 However, is this a DumbThingToDo™?然而,这是一个 DumbThingToDo™ 吗? I am never accessing ptr->data when it points to &myList as the loop terminates once ptr == &myList .ptr->data指向&myList时,我从不访问它,因为循环一旦ptr == &myList终止。

TLDR TLDR

In C structs, a Base* can point to a Derived if Base is the first member in Derived .在 C 结构中,如果BaseDerived中的第一个成员,则Base*可以指向Derived Can a Derived* point to a Base if none of Derived specific members are accessed?如果没有Derived特定成员被访问, Derived*是否可以指向Base

EDIT : replaced relevant function calls with their equivalent inline code.编辑:用等效的内联代码替换了相关的函数调用。

Kudos for your presentation.感谢您的介绍。

I think your implementation should work fine, because C guarantees that the address of a struct is the address of its initial member.我认为您的实现应该可以正常工作,因为 C 保证结构的地址是其初始成员的地址。 Put aside the statements C makes about alignment of struct-members, this guarantee should mean that, as long as your implementation always puts Link as first member, this should not cause alignment issues.撇开 C 关于结构成员对齐的声明,这个保证应该意味着,只要你的实现总是把 Link 作为第一个成员,这就不应该导致对齐问题。

from here : C99 §6.7.2.1:这里:C99 §6.7.2.1:

13 Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. 13 在结构对象中,非位域成员和位域所在的单元的地址按它们声明的顺序增加。 A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.指向结构对象的指针,经过适当转换,指向其初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。 There may be unnamed padding within a structure object, but not at its beginning结构对象内可能有未命名的填充,但不是在其开头

This should be what you meant to say about Base * and Derived * , although no such thing exists in pure C. They are just structs which happen to have the same memory layout.这应该是你想说的Base *Derived * ,尽管纯 C 中不存在这样的东西。它们只是恰好具有相同内存布局的结构。

However I think it is a bit brittle to implement it like this, because Node and Link directly depend on each other.但是我认为这样实现它有点脆弱,因为 Node 和 Link 直接相互依赖。 If you were to change the structure of Node, your code would become invalid.如果您要更改 Node 的结构,您的代码将失效。 At the moment I don't see the point in having an extra struct Link , apart from you being able to just write a new Node for a new type reusing Link.目前,我不认为拥有额外的struct Link ,除了您可以为重用 Link 的新类型编写一个新节点。

There is actually a linked list implementation that immediately came to mind when I saw your post and works in a way very similar to the way you intend to use your list: the kernel list当我看到您的帖子时,我立即想到了一个链表实现,它的工作方式与您打算使用列表的方式非常相似: 内核列表

It uses the same List-element ( list_head ):它使用相同的列表元素( list_head ):

struct list_head {
    struct list_head *next, *prev;
};

It contains this function macro:它包含这个函数宏:

#define list_for_each_entry(pos, head, member)                          \
      for (pos = list_first_entry(head, typeof(*pos), member);        \
           &pos->member != (head);                                    \
           pos = list_next_entry(pos, member))

If you look at the way the macro is implemented, you will see that it offers iteration over the entries of a list without knowing anything about the layout of the entries the list is contained in. Assuming I interpret your intention right, I think this is the way you would want it to be.如果您查看宏的实现方式,您将看到它提供对列表条目的迭代,而无需了解包含列表的条目的布局。假设我正确解释了您的意图,我认为这是你想要的样子。

In C structs, a Base* can point to a Derived if Base is the first member in Derived.在 C 结构中,如果 Base 是 Derived 中的第一个成员,则 Base* 可以指向 Derived。 Can a Derived* point to a Base if none of Derived specific members are accessed?如果没有派生特定成员被访问,派生*是否可以指向基类?

If you mean "can a Derived* point to an arbitrary Base (including one which is not a first member of a Derived object)", then: Technically, no.如果您的意思是“派生 * 可以指向任意基(包括不是派生对象的第一个成员的基)”,那么:从技术上讲,不可以。 My understanding of Defect Report #74 is the alignment requirements can be different.我对缺陷报告 #74 的理解是对齐要求可能不同。

Q: If a structure has a field of type t, can the alignment requirements of the field be different from the alignment requirements of objects of the same type that are not members of structures?问:如果一个结构体有一个类型为t的字段,那么该字段的对齐要求是否可以与非结构体成员的同类型对象的对齐要求不同? If the answer to (a) is ``yes,'' then where applicable the remaining questions should be assumed to have been asked for both objects within structures and objects outside structures.如果对 (a) 的回答是“是”,那么在适用的情况下,其余的问题应该假设已经针对结构内的对象和结构外的对象提出了要求。

A: Subclause 6.1.2.5 says, '... pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements.'答:第 6.1.2.5 节说,“……指向兼容类型的合格或不合格版本的指针应具有相同的表示和对齐要求。” Subclause 6.5.2.1 says, `Each non-bit-field member of a structure or union object is aligned in an implementation-defined manner appropriate to its type.'子条款 6.5.2.1 说,“结构或联合对象的每个非位域成员都以适合其类型的实现定义方式对齐。” And later, 'There may therefore be unnamed padding within a structure object, ... as necessary to achieve the appropriate alignment.'稍后,“因此,结构对象中可能存在未命名的填充,......这是实现适当对齐所必需的。” a) It is possible for an implementation to state generalized requirements to satisfy sublause 6.1.2.5. a) 实现可以声明满足 6.1.2.5 条的通用要求。 These requirements may be further strengthened using the implementation-defined behavior made available in subclause 6.5.2.1.可以使用第 6.5.2.1 节中提供的实现定义行为进一步加强这些要求。 Yes, the alignment requirements can be different.是的,对齐要求可能不同。

I wrote this in the comments to ouah's answer, but I'll present it as an answer in its own right.我在对 ouah 的回答的评论中写了这个,但我会将它作为自己的答案呈现。

It is true as ouah writes that the code in your question could have an alignment problem in theory if you go by the C standard.正如 ouah 所写的那样,如果您遵循 C 标准,那么理论上您的问题中的代码可能存在对齐问题。 However, I don't think there's a single architecture that your code is likely (or unlikely) to run on whose ABI exhibits such alignment patterns.但是,我认为您的代码可能(或不太可能)运行的单一架构的 ABI 表现出这种对齐模式。 At least none that I know of, for sure, and that includes experience with a few different desktop and embedded architectures.至少我所知道的没有,当然,这包括使用一些不同的桌面和嵌入式架构的经验。 I can also not really imagine an architecture that would gain anything from such alignment properties.我也无法想象一个架构会从这种对齐属性中获得任何好处。

It is also worth noting that this pattern is indeed used in practice quite commonly;还值得注意的是,这种模式确实在实践中使用得非常普遍; it's kind of like the fact that you can always fit int s in pointers, in that it's not guaranteed by any cross-platform standard, but there's virtually no platform on which it's not true, and people do it all the time.这有点像你总是可以在指针中放入int的事实,因为任何跨平台标准都不能保证它,但实际上没有平台不正确,人们一直这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM