Выделение одного указателя структуры другому – 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. Поскольку макет памяти 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 } 

Чаще всего я представляю реализации, где «родительский» class определяется как первый член «дочернего» classа, например:

 typedef struct { enum type type; } object; typedef struct { object parent; object *car; object *cdr; } cons_object; 

Это работает в основном таким же образом, за исключением того, что у вас есть сильный gaurantee, что макет памяти дочерних «classов» будет таким же, как и у родителей. То есть, если вы добавите элемент к базовому object , он автоматически будет подхвачен дочерними элементами, и вам не придется вручную проверять синхронизацию всех структур.

Чтобы добавить к ответу Дина, вот что-то о конверсиях указателей в целом. Я забыл, для чего этот термин, но указатель на листинг указателя не выполняет преобразование (так же, как int to float is). Это просто переинтерпретация бит, на который они указывают (все для выгоды компилятора). «Неразрушающая конверсия» Я так думаю. Данные не изменяются, только то, как компилятор интерпретирует то, на что указывает.

например,
Если ptr является указателем на object , компилятор знает, что существует поле с определенным смещением с именем type типа enum type . С другой стороны, если ptr cons_object указателю на другой тип 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 к указателю на структуру.

Если указатель был перенесен на указатель на object :

  +---+---+---+---+ ((object *)ptr) -> | t | y | p | e | enum type +---+---+---+---+ | c | a | r | | +---+---+---+---+ | c | d | r | | +---+---+---+---+ 

Весь компилятор должен знать, что существует поле под названием type со смещением 0. Все, что находится в памяти, находится в памяти.

Указатели даже не должны быть связаны вообще. У вас может быть указатель на int и cons_object его указателю на объект cons_object . Если бы вы получили доступ к полю car , это точно так же, как любой обычный доступ к памяти. Он имеет некоторое смещение от начала структуры. В этом случае то, что находится в этой ячейке памяти, неизвестно, но это неважно. Для доступа к полю требуется только смещение и информация содержится в определении типа.

Указатель на int указывает на блок памяти:

  +---+---+---+---+ int *ptr -> | i | n | t | | int +---+---+---+---+ 

cons_object указатель 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

Использование встроенной структуры, как в последнем примере Дин, прекрасно.

  • Не уникальные значения enums
  • Как определить структуру в Matlab
  • Назначить одну структуру другому в C
  • Класс смешивания и структура
  • bds 2006 C конфликты с скрытым диспетчером памяти (class new / delete vs. AnsiString)
  • memcpy vs назначение в C
  • Почему компиляторы C не могут изменять элементы структуры для исключения выравнивания?
  • структурированная сериализация в C и передача через MPI
  • Структурный конструктор в C ++?
  • Каковы различия между структурой и classом в C ++?
  • Что такое «форвардная декларация» и разница между «typedef struct X» и «struct X»?
  • Interesting Posts

    Android – как получать трансляции намерения ACTION_SCREEN_ON / OFF?

    Вычислить расстояние между 2 координатами GPS

    Перенос файлов по SSH

    Почему автобоксирование делает некоторые вызовы неоднозначными на Java?

    Инструмент / метод Java для принудительного уничтожения дочернего процесса

    Ошибка установки Skype; Код 1638 при попытке обновления Skype

    Какой лучший способ сортировать по 5-звездочному рейтингу?

    Как создать отдельную подсеть для беспроводного доступа?

    Проверьте, является ли ввод целым типом в C

    Поиск буквы диска из недавно смонтированного файла xvhd или vhd в пакете?

    Почему мой .bashrc читается, когда я запускаю неинтерактивные команды по ssh

    Каков второй параметр NSLocalizedString ()?

    Обновление кадра данных с помощью функции не работает

    Использование ЦП на 100% в течение нескольких часов

    Почему частота кадров в WPF нерегулярна и не ограничена для мониторинга обновления?

    Давайте будем гением компьютера.