한 구조체 포인터를 다른 구조체 포인터로 캐스팅 - C
다음 코드를 고려해주시기 바랍니다.
enum type {CONS, ATOM, FUNC, LAMBDA};
typedef struct{
enum type type;
} object;
typedef struct {
enum type type;
object *car;
object *cdr;
} cons_object;
object *cons (object *first, object *second) {
cons_object *ptr = (cons_object *) malloc (sizeof (cons_object));
ptr->type = CONS;
ptr->car = first;
ptr->cdr = second;
return (object *) ptr;
}
에서cons
함수, 변수ptr
유형의cons_object*
그러나 반환 값에서는 다음 유형으로 변환됩니다.object*
.
- 저는 어떻게 이것이 가능한지 궁금합니다. 왜냐하면
cons_object
그리고.object
서로 다른 구조입니다. - 이런 일을 하는데 문제가 있습니까?
아무 생각 없이!
이것은 괜찮고 C에서 "객체 지향"을 구현하기 위한 상당히 일반적인 기술입니다.왜냐하면 메모리 레이아웃이struct
s는 C에서 잘 정의되어 있습니다. 두 개체가 동일한 레이아웃을 공유하는 한 두 개체 사이에 포인터를 안전하게 캐스팅할 수 있습니다.즉, 간격띄우기type
구성원은 에서 동일합니다.object
있는 그대로의 구조cons_object
구조의
이 경우,type
구성원이 API에 알려줍니다.object
이다.cons_object
또는foo_object
또는 다른 종류의 물체를 볼 수 있으므로 다음과 같은 것을 볼 수 있습니다.
void traverse(object *obj)
{
if (obj->type == CONS) {
cons_object *cons = (cons_object *)obj;
traverse(cons->car);
traverse(cons->cdr);
} else if (obj->type == FOO) {
foo_object *foo = (foo_object *)obj;
traverse_foo(foo);
} else ... etc
}
좀 더 일반적으로, "부모" 클래스가 "자녀" 클래스의 첫 번째 멤버로 정의되는 구현체는 다음과 같습니다.
typedef struct {
enum type type;
} object;
typedef struct {
object parent;
object *car;
object *cdr;
} cons_object;
이것은 아이들의 "수업"의 기억 배치가 부모들과 같을 것이라는 것을 강력하게 인식하고 있다는 것을 제외하면 거의 같은 방식으로 작동합니다.즉, '기본'에 구성원을 추가하는 경우object
아이들이 자동으로 집어서 모든 구조가 일치하는지 수동으로 확인할 필요가 없습니다.
딘의 대답에 덧붙여, 여기 일반적으로 포인터 변환에 관한 것이 있습니다.이것에 대한 용어가 무엇인지 잊었지만 포인터 캐스트에 대한 포인터는 변환을 수행하지 않습니다(플로트에 대한 포인터와 동일한 방식).이는 단순히 그들이 가리키는 비트를 재해석한 것입니다(모두 컴파일러의 이익을 위해)."비파괴적 전환"이었던 것 같습니다.데이터는 변경되지 않고 컴파일러가 가리키는 것을 해석하는 방법만 변경됩니다.
예.,
한다면ptr
에 대한 포인터입니다.object
컴파일러는 이름이 지정된 특정 오프셋을 가진 필드가 있다는 것을 알고 있습니다.type
유형의enum type
반면에 만약에ptr
다른 유형의 포인터에 캐스팅됩니다.cons_object
다시 그것은 그것의 필드에 접근하는 방법을 알게 될 것입니다.cons_object
비슷한 방식으로 각각의 오프셋을 가지고 있습니다.
메모리 레이아웃을 예로 들어 설명합니다.cons_object
:
+---+---+---+---+
cons_object *ptr -> | t | y | p | e | enum type
+---+---+---+---+
| c | a | r | | object *
+---+---+---+---+
| c | d | r | | object *
+---+---+---+---+
그type
필드에 오프셋 0이 있습니다.car
4입니다.cdr
8입니다. 카 필드에 액세스하기 위해 컴파일러가 해야 할 일은 추가하는 것입니다.4
구조물 포인터로 이동합니다.
▁to의 포인터에 된 경우object
:
+---+---+---+---+
((object *)ptr) -> | t | y | p | e | enum type
+---+---+---+---+
| c | a | r | |
+---+---+---+---+
| c | d | r | |
+---+---+---+---+
할 은 컴일러알할것다것같라는 입니다.type
속에 것은 기억 속에 .기억 속에 있는 것은 무엇이든 기억 속에 있습니다.
포인터들은 어떤 것과도 연관될 필요가 없습니다.에 대한 포인터를 가질 수 있습니다.int
그리고 그것을 포인터로 던집니다.cons_object
에 할 수 ,car
필드, 그것은 일반적인 메모리 액세스와 같습니다.구조체의 시작 부분부터 일정한 간격띄우기가 있습니다.이 경우 해당 메모리 위치에 무엇이 있는지 알 수 없지만 중요하지 않습니다.필드에 액세스하려면 오프셋만 필요하며 해당 정보는 유형의 정의에서 찾을 수 있습니다.
에 대한 int
메모리 블록을 가리킵니다.
+---+---+---+---+
int *ptr -> | i | n | t | | int
+---+---+---+---+
에캐팅됨에 된.cons_object
포인터:
+---+---+---+---+
((cons_object *)ptr) -> | i | n | t | | enum type
+---+---+---+---+
| X | X | X | X | object *
+---+---+---+---+
| X | X | X | X | object *
+---+---+---+---+
별도의 구조체를 사용하는 것은 엄격한 별칭 규칙을 위반하며 정의되지 않은 동작입니다. http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html
딘의 마지막 예와 같이 내장된 구조를 사용하는 것은 괜찮습니다.
언급URL : https://stackoverflow.com/questions/3766229/casting-one-struct-pointer-to-another-c
'it-source' 카테고리의 다른 글
Json 객체를 에이잭스에서 스프링 mvc 컨트롤러로 전달하는 방법은 무엇입니까? (0) | 2023.07.30 |
---|---|
5초마다 jQuery/Ajax로 테이블 새로 고침 (0) | 2023.07.30 |
SQL Server에서 !=와 <>의 차이점 (0) | 2023.07.30 |
Spring MVC 컨트롤러 테스트에서 서비스 클래스를 모의 실행할 수 없습니다. (0) | 2023.07.30 |
Oracle의 LEFT 함수 (0) | 2023.07.30 |