C 구조체에 관련된 여러가지
핀토스 과정 중 배운 트릭
Code(C)
/* Converts pointer to list element LIST_ELEM into a pointer to
the structure that LIST_ELEM is embedded inside. Supply the
name of the outer structure STRUCT and the member name MEMBER
of the list element. See the big comment at the top of the
file for an example. */
#define list_entry(LIST_ELEM, STRUCT, MEMBER) \
((STRUCT *) ((uint8_t *) &(LIST_ELEM)->next \
- offsetof (STRUCT, MEMBER.next)))
위의 코드는 무엇을 말하고 있을까?
/* List element. */
struct list_elem {
struct list_elem *prev; /* Previous list element. */
struct list_elem *next; /* Next list element. */
};
/* List. */
struct list {
struct list_elem head; /* List head. */
struct list_elem tail; /* List tail. */
};
위의 구조체에서 아래와 같은 방식으로 각 구조체 요소를 구해올 수 있었다
list_entry (&aElement, struct semaphore_elem, elem);
그렇다면 위의 define은 어떻게 작동할까?
먼저 offsetof에 대하여 보자
/* Offset of member MEMBER in a struct of type TYPE. */
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
컴파일러 내장 함수인 ‘__builtin_offsetof’는
struct 나 union 의 멤버가 있는 ‘오프셋’을 바이트 단위로 반환한다
이는 ‘해당 구조체의 시작부터 얼마나 떨어져 있는지’를 나타내며
그렇기에
‘offsetof (STRUCT, MEMBER.next)’는
STRUCT 에 존재하는 MEMBER.next의 오프셋을 반환한다
(위의 예시로 말하면, semaphore_elem 내부에서 elem의 요소까지의 offset을
반환한다)
그리고 ‘&(LIST_ELEM)->next’
는 현재 (LIST_ELEM)->next 의 주소를 나타내며,
이는 list_elem 내부의 ‘next’ 멤버의 위치를 표현한다
이후, 아래의 그림처럼 빼기 연산을 통하여
해당 list_elem을 가지고 있는 구조체의 시작 위치를 반환한다
이후 마지막으로 , (STRUCT *)로 캐스팅하여
해당하는 구조체 타입으로 반환한다
해당 내용을 확인하니,
thread 내부에서,
elem 과 wait_elem 용으로 2개의 elem을 두었을 때
list_entry(list_front(&thread_current()->waitList),struct thread,waitElem)
해당 코드에서 waitElem 대신, elem을 넣었을 때,
예상치 못한 동작이 발생할 수 있다는 것을 확인할 수 있었다
(waitList에 들어있는 것이 waitElem 일 때,
list_entry(,,elem)으로 사용한 경우,
반환되는 offset이 구조체의 elem 기준이기에
구조체의 시작위치를 정확히 가리키지 않는다)
댓글남기기