it-source

한 구조체 포인터를 다른 구조체 포인터로 캐스팅 - C

criticalcode 2023. 7. 30. 17:54
반응형

한 구조체 포인터를 다른 구조체 포인터로 캐스팅 - 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*.

  1. 저는 어떻게 이것이 가능한지 궁금합니다. 왜냐하면cons_object그리고.object서로 다른 구조입니다.
  2. 이런 일을 하는데 문제가 있습니까?

아무 생각 없이!

이것은 괜찮고 C에서 "객체 지향"을 구현하기 위한 상당히 일반적인 기술입니다.왜냐하면 메모리 레이아웃이structs는 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이 있습니다.car4입니다.cdr8입니다. 카 필드에 액세스하기 위해 컴파일러가 해야 할 일은 추가하는 것입니다.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

반응형