Как член объединения может иметь указатель на экземпляр объединения? - PullRequest
0 голосов
/ 27 февраля 2019

Возможно, я слишком усложняю это.

Я пытаюсь создать довольно многоразовую систему иерархических меню для встроенного приложения в C на Arduino.У меня есть структуры для представления различных типов пунктов меню, включая те, которые являются подменю, и объединение этих элементов в общий пункт меню.Массив пунктов меню - это один уровень меню.Запись подменю имеет указатель на другой массив пунктов меню.

Проблема в том, что запись подменю является членом объединения, поэтому ее необходимо определить до объединения.Но у него есть указатель на массив экземпляров этого объединения, что приводит к ошибке компиляции, потому что объединение еще не определено.

Есть ли безопасный способ решения этой проблемы или мой указатель находится в записи подменюдолжна быть пустота *?

Код:

typedef enum {UI_STATE_HOME, UI_STATE_MENU, UI_STATE_DIALOG} te_UIState;
typedef enum {UI_ENTRY_SUBMENU, UI_ENTRY_NUMERIC_INT, UI_ENTRY_NUMERIC_FLOAT, UI_ENTRY_BOOL, UI_ENTRY_DISCRETE} te_UIEntryType;

/* Typedefs for the different types of entry
 *  
 */

typedef struct {
  char* entryName; // pointer to one of our string entries, eg MNU_Light
  te_UIEntryType entryType;
} tsEntry;

typedef struct {
  char* entryName;
  te_UIEntryType entryType;
  int (* finalIntHandler)(int selectedValue); //The function that should be called when a number has been selected
  int (* initialIntValue) (); //The function that should be called to obtain the starting value for the selector
} ts_EntryInt;

typedef struct {
  char* entryName;
  te_UIEntryType entryType;
  int (* finalIntHandler)(float selectedValue);
  float (* initialSingleValue) ();
} ts_EntrySingle;

typedef struct {
  char* entryName;
  te_UIEntryType entryType;
  int (* finalIntHandler)(bool selectedValue);
  bool (* initialBoolValue) ();
} ts_EntryBool;

typedef struct {
  char* entryName;
  te_UIEntryType entryType;
  int (* handler)();
  char* (* optionalEntryNamePtrFunction)(); //If this points to a function, it'll be called to determine what text to display as the entry name.
  // This is for things like enable/disable where the text changes depending on the present state.
} ts_EntryDiscrete;

typedef struct {
  char* entryName;
  const te_UIEntryType entryType = UI_ENTRY_SUBMENU;
  void *entries[];
} ts_EntrySubmenu;


typedef union
{
  tsEntry entry;
  ts_EntryInt entryInt;
  ts_EntrySingle entrySingle;
  ts_EntryBool entryBool;
  ts_EntryDiscrete entryDiscrete;
  ts_EntrySubmenu entrySubmenu;
} tuEntry;

Ответы [ 3 ]

0 голосов
/ 27 февраля 2019

Вам необходимо переслать объявление tuEntry, чтобы вы могли использовать его в ts_EntrySubmenu.Вам нужно будет дать имя тега этому объединению, чтобы на него можно было ссылаться позже.

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

typedef union tuEntry tuEntry;

typedef struct {
  char* entryName;
  const te_UIEntryType entryType;   // no default value
  tuEntry *entries[];
} ts_EntrySubmenu;


union tuEntry
{
  tsEntry entry;
  ts_EntryInt entryInt;
  ts_EntrySingle entrySingle;
  ts_EntryBool entryBool;
  ts_EntryDiscrete entryDiscrete;
  ts_EntrySubmenu entrySubmenu;
};
0 голосов
/ 27 февраля 2019

Проблема в том, что элемент подменю является членом объединения, поэтому его необходимо определить до объединения.

Да.

Ноу него есть указатель на массив экземпляров этого объединения, что вызывает ошибку компиляции, потому что объединение еще не определено.

Не требуется определять объединение, чтобы объявить указатель наэтот тип.Нужно только, чтобы было объявлено .Определение может появиться позже.

Есть ли безопасный способ решения этой проблемы, или мой указатель в записи подменю должен быть пустым *?

Да,Форвард-объявлять объединение перед определением структуры, а потом помещать определение объединения.Это требует от вас предоставления тега для вашего типа объединения, иначе предварительное объявление и последующее определение не будут ссылаться на тот же тип.

Пример:

typedef union entry tuEntry;

typedef struct {
  // ...
  tuEntry *entries[];
} ts_EntrySubmenu;


union entry
{
  // ...
  ts_EntrySubmenu entrySubmenu;
};

Дополнительно,Я не могу не заметить, что ваш исходный код полностью избегает объявления какой-либо структуры или тегов объединения.Я хочу убедиться, что вы понимаете, что это стиль выбора , и особенно, что ключевое слово typedef не для определения типов, а скорее для объявления псевдонимов для имен типов.Ваш стиль по своей сути не ошибочен, но он не поддерживает то, что вы хотите сделать.Вам необходимо использовать типы структур и объединений с тегами, чтобы связать несколько объявлений одного и того же типа в одной и той же области видимости.

0 голосов
/ 27 февраля 2019

Объявление указателя на некоторый T требует только объявления T, не обязательно определенного.Так что просто сделайте это:

union Entry;

typedef struct {
  char* entryName;
  const te_UIEntryType entryType = UI_ENTRY_SUBMENU;
  union Entry *entries[];
} ts_EntrySubmenu;

typedef union Entry {
  /* as before */
} tsEntry;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...