CONTAINING_RECORD 매크로
5221 단어 contain
=========================
전재 하 다
매크로 CONTAININGRECORD 의 용 도 는 사실 상당히 크 고 편리 하 다. 그 주요 역할 은 구조 체 중의 한 구성원 의 지침 에 따라 이 구조 체 의 지침 을 추산 하 는 것 이다!다음은 간단 한 예 에서 시작 합 니 다. 우 리 는 하나의 구조 체 를 정의 하고 유형 화 합 니 다.
typedef struct{
int a;
int b;
int c;
}ss;
이것 은 매우 간단 한 구조 체 입 니 다. 특별한 것 이 없습니다. 이 구조 체 를 조금 분석 해 보 세 요. 구조 체 의 크기 (바이트): 4 + 4 + 4 = 12 바이트 구성원 a 의 오프셋: 0 구성원 b 의 오프셋: 4 구성원 c 의 오프셋: 8 우 리 는 ss 로 변 수 를 정의 합 니 다. ss = {1, 2, 3};그러면 이때 a, b, c 의 값 은 각각 a = 1, b = 2, c = 3 이다. 사실 컴 파일 러 는 코드 를 생 성 할 때 이렇게 구성원 변수 에 값 을 부여 한다. s 의 주 소 는 0 x 12000000 이 라 고 가정 하면 * (int *) (char *) & s + 0 = 1 이다. *(int*)((char*)&s + 4) = 2; *(int*)((char*)&s + 8) = 3;즉, & s 의 주 소 를 바탕 으로 변수의 오프셋 을 추가 하여 구성원 의 지침 을 확인 하고 값 을 부여 하 는 것 입 니 다. 따라서 & s - > a 는 0x12000000 + 0 = 0x12000000 & s - > b 는 0x12000000 + 4 = 0x120000004 & s - > c 는 0x12000000 + 8 = 0x120000008 을 얻 을 것 입 니 다. + 구성원 변수의 오프셋 = 구성원 변수의 주소 이동 항목: 구성원 변수의 주소 - 구성원 변수의 오프셋 = 구조 체 의 주 소 는 이것 이 바로 우리 가 원 하 는 주소 입 니 다. 바로 뺄셈 을 한 것 이 아 닙 니까? 우선, 구성원 변수의 주 소 는 우리 가 알 고 있 습 니 다. 그 다음 에 우 리 는 구성원 변수의 오프셋 (구성원 b 의 오프셋 으로 가정) 을 받 아야 합 니 다. 어떻게 해 야 합 니까?우 리 는 이렇게 할 수 있다: & s - > b - (unsigned long) & s, 그러면 멤버 b 의 오프셋 을 얻 을 수 있다. 그러나, & s 는 우리 가 필요 로 하 는 것 이다. 분명히 잠시 미지수 이다. 그렇다면... 우리 다시 한 번 뺄셈 을 하 자 (정확 하지 않 은 C 언어 표현 식 이지 만 결 과 는 문제 가 없다. 여 기 는 단지 명확 하 게 보일 뿐이다): & (s - s) - > b -(unsinged long)&(s-s), 그 중에서 유형 이 일치 하도록 하기 위해 서 는 s - s = (ss *) 0 (unsigned long) & (s - s) = (unsigned long) (ss *) 0 = 0 을 직접 생략 하면 됩 니 다. 그러면 화 간 은 & (ss *) 0 - > b - (unsigned long) 0 의 가장 간단 한 결 과 를 얻 을 수 있 습 니 다. & (ss *) 0)- > b, 이것 이 바로 b 의 오프셋 입 니 다 하하, 간단 하 죠? 0 포인터 의 묘 미 는 모두 두 번 의 감법 을 했 을 뿐 입 니 다. 그 중에서 우 리 는 ss 구조 체 의 원형, ss 구조 체 중의 한 구성원 변수 b (사실은 어느 것 이 든 똑 같 습 니 다. 앞에서 지침 을 제공 하 는 그 변수 와 일치 해 야 합 니 다)요약 하면 저 희 는 구조 체 중의 한 구성원 변수의 주소, 이 구조 체 의 원형, 이 구조 체 중의 한 구성원 변수 (앞에서 같은 변수 라면) 의 최종 CONTAINING RECORD 의 정 의 를 제공 해 야 합 니 다.
#define CONTAINING_RECORD(addr,type,field) ((type*)((unsigned char*)addr - (unsigned long)&((type*)0)->field))
addr:
type:
field: ( )
자, 모든 결론 이 나 왔 습 니 다. 이것 은 만능 공식 입 니 다. 멤버 변수 가 어떤 결과 든 정확 합 니 다. 이것 은 첫 번 째 변 수 를 아 는 주소 에 비해 첫 번 째 멤버 의 주소 (pa = & s - > a) 를 알 고 있다 면 가장 간단 한 상황 입 니 다. 유형 전환 을 직접 강제 하면 됩 니 다. (ss *) pa 면 됩 니 다. 이때 & (s)(type *) 0) - > field 이 부분 은 마침 0 이기 때문에 결 과 는 바로 (type *) addr 입 니 다. 가장 간단 한 상황 입 니 다. 또한 우리 가 가장 쉽게 생각 할 수 있 는 상황 입 니 다. 예 를 들 어 링크 요 소 를 구조 체 의 초기 에 두 는 것 입 니 다. 여기까지 이 CONTAINING RECORD 매크로 는 이미 말 을 마 쳤 습 니 다. 지금 은 LIST ENTRY 등 양 방향 링크 를 사용 할 때 이 링크 를 구조 체 의 어느 곳 에 두 든 링크 를 옮 겨 다 닐 때 CONTAINING RECORD 매크로 를 통 해 전체 구조 체 의 주 소 를 정확하게 얻 을 수 있 습 니 다. 링크 의 특정한 요 소 를 제거 할 때 free 전체 구조 체 의 주 소 를 기억 해 야 합 니 다.그래 야 합 니 다. WDK 가 제공 하 는 조작 함 수 는 이 링크 요 소 를 전체 링크 에서 벗 어 나 addr 를 unsigned char * 로 바 꾸 는 이 유 는 포인터 로 계산 할 때 계산 단위 가 1 이기 때 문 입 니 다. 즉, (unsigned char *) addr + 1 = addr + 1, 바 꾸 지 않 으 면 잘못된 것 입 니 다 & (type *) 0 - > field 를 (unsigned long) 으로 바 꾸 는 것 입 니 다.4 개의 바이트 가 넓 은 동시에 표현 식 이 두 개의 포인터 의 산술 조작 으로 구 성 된 것 이 아니 라 C 언어 표준 이 그러한 연산 을 정의 하지 않 았 기 때 문 입 니 다.