C 구조 상속 포인터 정렬
배경
저는 주로 학습 목적으로 기본 링크 리스트 데이터 구조를 만들었습니다.이 목록의 한 가지 목표는 다양한 데이터 구조를 처리할 수 있다는 것이었습니다.그래서 C로 상속을 시뮬레이트하기 위해 구조구성을 시도했습니다.링크 리스트의 기반이 되는 구조는 다음과 같습니다.
typedef struct Link {
struct Link* next;
struct Link* prev;
} Link;
typedef Link List;
구현에서는 목록의 선두와 꼬리 역할을 하는 감시 노드를 선택했습니다(이것이 Link == List의 이유입니다).
리스트가 실제로 데이터를 처리하도록 하기 위해 구조체는 링크 구조를 첫 번째 멤버로 포함합니다.
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
포인터는 처음에 첫 번째 노드를 가리킵니다.그런 다음 다시 Sentinel을 가리킨 후 정지할 때까지 목록을 통과합니다.
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*
하지만 이것은 DumbThingToDo™입니까?액세스 할 수 없습니다.ptr->data
을 가리키면&myList
루프가 한 번 종료되면ptr == &myList
.
TLDR
C구조에서는Base*
을 가리킬 수 있다Derived
한다면Base
의 첫 번째 멤버입니다Derived
.카나Derived*
을 가리키다Base
어느 쪽도 아니라면Derived
특정 멤버에 접속되어 있습니까?
EDIT: 관련 함수 호출을 동등한 인라인 코드로 바꿉니다.
프레젠테이션에 찬사를 보냅니다.
C는 구조체의 주소가 초기 구성원의 주소임을 보증하기 때문에 당신의 구현은 잘 될 것이라고 생각합니다.구조 멤버의 얼라인먼트에 관한 C의 진술은 제쳐두고, 이 보증은 실장 시에 항상 링크가 첫 번째 멤버로 설정되어 있는 한 얼라인먼트 문제가 발생하지 않는다는 것을 의미합니다.
여기서: C99 § 6.7.2.1:
13 구조 오브젝트 내에서 비트필드가 아닌 멤버 및 비트필드가 존재하는 유닛은 선언된 순서대로 증가하는 주소를 가집니다.적절하게 변환된 구조 객체에 대한 포인터는 첫 번째 멤버(또는 해당 멤버가 비트필드인 경우 비트필드가 있는 유닛을 가리키며, 그 반대도 마찬가지입니다.구조체 개체 내에 이름 없는 패딩이 있을 수 있지만 그 시작에는 없습니다.
이것이 당신이 말하고자 했던 것이어야 합니다.Base *
그리고.Derived *
단, 순수 C에는 그러한 것이 존재하지 않는다.그것들은 우연히 같은 메모리 레이아웃을 가진 구조일 뿐이다.
다만, Node와 Link는 서로 직접 의존하기 때문에, 이렇게 실장하는 것은 조금 약하다고 생각합니다.노드 구조를 변경하면 코드가 비활성화됩니다.지금으로선 엑스트라 하나 더 가져도 소용없을 것 같아struct Link
Link를 사용하여 새로운 유형의 노드를 작성할 수 있습니다.
실제로 링크 리스트 실장이 있습니다.이 실장은 제가 당신의 투고를 보았을 때 바로 떠올랐습니다.커널 리스트와 같은 방법으로 동작합니다.
같은 리스트 요소를 사용합니다(list_head
):
struct list_head {
struct list_head *next, *prev;
};
여기에는 다음 함수 매크로가 포함됩니다.
#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))
매크로의 실장 방법을 보면, 리스트가 포함되는 엔트리의 레이아웃에 대해서는 아무것도 모르는 채, 리스트의 엔트리에 대해서 반복을 제공하고 있는 것을 알 수 있습니다.제가 당신의 의도를 올바르게 해석한다면, 이것이 당신이 원하는 방식이라고 생각합니다.
C 구조에서 베이스가 파생 멤버의 첫 번째 멤버인 경우 베이스*는 파생 멤버를 가리킬 수 있습니다.Derived*는 Derived 특정 구성원에 액세스할 수 없는 경우 Base를 가리킬 수 있습니까?
"파생*이 임의의 베이스(파생 오브젝트의 첫 번째 멤버가 아닌 베이스 포함)를 가리킬 수 있습니다"를 의미하는 경우, 다음과 같이 입력합니다.엄밀히 말하면 안 돼결함 보고서 #74에 대한 저의 이해는 얼라인먼트 요건이 다를 수 있다는 것입니다.
Q: 구조물에 t타입의 필드가 있는 경우, 필드의 정렬 요건은 구조물의 멤버가 아닌 동일한 유형의 객체의 정렬 요건과 다를 수 있습니까?(a)에 대한 대답이 "예"인 경우, 해당되는 경우 나머지 질문은 구조물 내의 객체와 구조물 외부의 객체 모두에 대해 질문된 것으로 가정해야 한다.
A: 하위조항 6.1.2.5는 '호환 가능한 형식의 적격 또는 부적격 버전에 대한 포인터는 동일한 표현 및 정렬 요건을 가져야 한다'고 말한다.하위조항 6.5.2.1은 '구조물 또는 유니언 객체의 비비트장 부재는 그 유형에 적합한 구현 정의 방식으로 정렬되어 있다'고 말한다.그리고 나중에 '따라서 구조 객체 내에 이름이 없는 패딩이 있을 수 있습니다.' a) 구현은 하위 조항 6.1.2.5를 충족하기 위해 일반화된 요구사항을 명시할 수 있습니다.이러한 요건은 하위 절 6.5.2.1에서 이용할 수 있는 구현 정의 행동을 사용하여 더욱 강화될 수 있다.네, 정렬 요건은 다를 수 있습니다.
와의 답변에 댓글로 썼지만 답변으로 제시하겠습니다.
당신이 C규격으로 진행한다면 당신의 질문의 코드는 이론적으로 얼라인먼트에 문제가 있을 수 있다고 ouah가 쓴 것은 사실입니다.그러나 ABI가 이러한 얼라인먼트 패턴을 보이는 경우 코드가 실행될 가능성이(또는 가능성이 낮은) 아키텍처는 없다고 생각합니다.적어도 제가 아는 바로는 없습니다.그것은 몇 가지 다른 데스크톱 아키텍처와 임베디드 아키텍처에 대한 경험이 포함되어 있습니다.또, 이러한 정렬 특성으로부터 아무것도 얻을 수 있는 아키텍처는, 실제로 상상할 수 없습니다.
이 패턴은 실제로 꽤 일반적으로 사용되고 있다는 것도 주목할 필요가 있습니다.그것은 당신이 항상 맞출 수 있다는 사실과 비슷합니다.int
포인터에서는 크로스 플랫폼 표준에서는 보증되지 않지만 실제로는 그렇지 않은 플랫폼이 존재하지 않으며 사람들은 항상 이 작업을 수행합니다.
언급URL : https://stackoverflow.com/questions/28179592/c-struct-inheritance-pointer-alignment
'programing' 카테고리의 다른 글
Vuex에서의 디바운스 사용방법 (0) | 2022.08.15 |
---|---|
Vuex: 복잡한 객체 및 상태 변경 기능 사용 (0) | 2022.08.15 |
Vuex getter에서 rootState에 액세스하는 중 (0) | 2022.08.15 |
Retrofit 2를 사용하여 모든 요청에 머리글 추가 (0) | 2022.08.15 |
$router로 데이터를 전달하려면 어떻게 해야 합니까?Vue.js를 밀어넣을까요? (0) | 2022.08.15 |