2016-12-14 4 views
1

This program - это другой подход к одному и тому же старому одиночному списку. Вместо создания единой структуры и сохранения указателя следующего узла того же типа, что и член структуры, я здесь использовал три разные структуры и простой член long nextaddress в каждом, чтобы указать адрес следующего узла, поскольку указатели также делают то же самое.Может ли структура данных содержать несколько типов элементов?

Каждый узел также имеет элемент int flag в качестве первого элемента структуры, а часть data находится в конце структуры из-за своей переменной длины.

Эти три конструкции являются базовыми расширениями встроенных типов, long, double и char. При обращении к структурам я сначала выбрал адрес узла как int *, что дает мне доступ к flag без полного наведения адреса на определенную структуру из трех.

Затем, анализируя flag, выполняются различные операции.

Итак, вот мой вопрос. Можно ли назвать действительный связанный список? И, кроме того, это даже действительная структура данных?

+0

Нет ничего плохого в узле связанного списка, содержащем несколько вещей. На самом деле это совершенно нормально. –

+0

Я думаю, это прекрасно, если это то, что вы хотите. Однако почему бы просто не сделать жизнь проще и иметь указатель на следующий узел? Если вы можете хранить и получать доступ к данным без проблем, то это действительная структура данных, а не очень распространенная. – RoadRunner

+0

Если я держу указатель на следующий узел, тогда мне придется держать все указатели других структур в каждой структуре и даже другой флаг, чтобы определить, что используется. Вот почему я использовал эту стратегию. @RoadRunner – Subhranil

ответ

0

Это нормально, если у вас есть средство для определения того, какой тип содержит каждый узел, например, переменная flag.

Кажется разумным, что вы можете предположить, что flag и nextaddress будут находиться на одинаковых смещениях структуры независимо от того, какой тип структуры вы используете. Хотя, строго говоря, язык C не гарантирует этого, я считаю, что он будет работать на практике в любой системе.

Однако вы не можете предположить, что data находится по адресу (uint8_t*)&my_struct + sizeof(int) + sizeof(long). Это смещение может варьироваться между структурами из-за разных требований к выравниванию.

Более серьезной проблемой является наложение указателя. Вы не можете взять указатель struct* x и преобразовать его в другой тип указателя struct* y. Он будет компилироваться, но это является нарушением правил типа в C и вызывает неопределенное поведение (если только обе структуры не имеют одинаковых членов). Стандартные компиляторы, которые используют агрессивные оптимизации (например, GCC), не будут компилировать такой код, как ожидалось. (What is the strict aliasing rule?)

Чтобы быть на безопасной стороне и получить лучший дизайн программы в целом, я рекомендовал бы, чтобы вы вместо того, чтобы сделать это:

typedef struct node 
{ 
    long nextaddress; 
    type_t type; // some enum 
    void* data; 
} node_t; 

Где data выделяется отдельно от узла. Вы получаете связанный список со списком.

+0

Я не выбрал 'struct * y' для' struct * x' и наоборот. Я только отправил адреса в gen_type, которые в соответствии со стандартом C полностью допустимы, и все четыре структуры будут следовать одному и тому же макету памяти для исходных общих членов.Никакое неназванное заполнение не начинается в начале, а не где-либо между «int flag» и «long nextaddress», поскольку оба являются полным кратным 4, что опять же, чтобы процитировать вас, «будет работать на практике в каждой системе '. Проблема заключается в части 'data', более конкретно в' node_type_char'. – Subhranil

+0

Это также можно преодолеть, используя некоторые вычисления.
'offset_of_data = sizeof (node) + start_address - sizeof (data)'
Чтобы быть ясным, я хочу, чтобы я мог иметь разные структуры в том же списке, гетерогенный связанный список, если можно. – Subhranil

+0

И тем временем весь код проверяется и компилируется в GCC. Поэтому я не совсем уверен в агрессивной оптимизации. – Subhranil

2

Ваш код имеет много проблем, но только со ссылкой на конкретные вопросы о структурах

Standard C грантов, который работает у вас решение

6.7.2.1 Структура и объединение спецификаторов

Sub глава 15

Внутри объекта структуры, элементы небитового поля и единицы, в которых бит -fields имеют адреса, которые увеличиваются в том порядке, в котором они объявлены. Указатель на объект структурной структуры , соответствующим образом преобразованный, указывает на его исходный элемент (или если этот элемент является битовым полем , а затем к устройству, в котором он находится) и наоборот. В объекте структуры может быть не указано , но не в начале.

Упор шахта

Вы должны использовать gen_struct внутри другой структуры: это дает соблюдать правило «начального члена».

struct gen_type { 
    int flag; 
    void *nextaddress; 
}; 

struct node_type_int { 
    struct gen_type header; 
    long data; 
}; 

struct node_type_real { 
    struct gen_type header; 
    double data; 
}; 

struct node_type_char { 
    struct gen_type header; 
    char data; 
}; 

Как вы можете видеть, что я также изменил тип из nextaddress: предназначается, чтобы быть указателем, поэтому используйте указатель.

Примечание стороны: do-i-cast-the-result-of-malloc

+0

Однако стандарт C не гарантирует, что 'dataaddress = ((long) (& generic-> nextaddress)) + sizeof (long);' работает. Кроме того, в коде существуют проблемы с псевдонимом указателя. – Lundin

+0

@Marian Вопросы: _Каким ли он называется действительным связанным списком? И, кроме того, это даже действительная структура данных? _ Так что это не обзор кода, или проверьте мою службу кода. Я указал на часть кода OP, связанного с вопросами. – LPs

+0

@LP В моем понимании речь идет о конкретном коде, представленном в ссылке. Ваш ответ может создать впечатление, что код OP действителен, пока он отсутствует. С другой стороны, ваш код действителен. – Marian

0

Ницца. Из коробки мне понравился другой способ сделать это! но ...

Учитывая выравнивания памяти различия по не вы чувствуете, что может быть проблемой с ниже код:

dataaddress = ((long)(&generic->nextaddress)) + sizeof(long); 

Здесь вы предполагаем, что данные непрерывно сохраняются и, следовательно, вычисление адреса данных путем добавления SizeOf длиной до адрес следующего адреса. Но это не всегда так правильно?

Вместо этого, я чувствую, что он лучше приведения к соответствующему типу структуры после считывания значения флага, а затем чтения данных.

Учитывая такие проблемы, хотя вы сохраняете какую-то память, но добавляете еще немного обработки. Таким образом, хотя это похоже на действительный связанный список, реализация может быть решена при выборе памяти и обработки.

+0

Yup, это конечная точка. Хотя обработку трудно представить и реализовать с точки зрения программиста, я не думаю, что для выполнения некоторых простых дополнений и адресации потребуется много накладных расходов, по сравнению с утечкой нескольких байтов в каждом экземпляре , Я предпочел бы иметь компактную память за несколько секунд обработки. Что сказать? – Subhranil

0

Ваш код имеет по крайней мере две слабые точки:

1.) преобразование между long и указателем и обратно. Стандарт C позволяет это только в том случае, если целочисленный тип может содержать необходимый диапазон, что может быть не так на архитектурах с 32-разрядными целыми числами long и 64-разрядными указателями.

Я добавление цитаты из стандарта C11, раздел 6.3.2.3 Указателей:

Целого числа может быть преобразованы в любой тип указателя. За исключением случаев, как ранее указано, результат от реализации, может не быть правильно выровнены, может не указывать на сущности ссылочного типа, и может быть ловушка representation.67)

Любой тип указателя может быть преобразован к целочисленному типу. За исключением случаев, указанных ранее, результат определяется реализацией. Если результат не может быть представлен в целочисленном типе, то поведение не определено. Результат не должен быть в диапазоне значений любого целого числа .

67) Функция отображения для преобразования указателя в целое или целое число в указатель предназначены для соответствовать адресациям структуры среды исполнения

2.) предполагает, что реализация пола в две разные структуры (где совпадают типы совпадающих полей) хранятся в одном и том же месте (смещение) внутри структуры. Хотя это справедливо для большинства реализаций, стандарт гарантирует это только в том случае, если эти две структуры являются частью союза.

Раздел 6.5.2.3 Структура и члены профсоюзов:

Особая гарантия делаются для того, чтобы упростить использование союзов: если объединение содержит несколько структур, которые разделяют общую начальную последовательности (см ниже) , и если объект объединения в настоящее время содержит одну из этих структур, разрешается проверять общую начальную часть любого из них в любом месте, где видна декларация завершенного типа объединения . Структуры Tw o имеют общую начальную последовательность, если соответствующие члены имеют совместимые типы (и для битовых полей одинаковой ширины) для последовательности из одного или нескольких начальных элементов .