我可能把这个复杂化了。
我正在尝试在Arduino上的C语言中为嵌入式应用程序创建可重用的分层菜单系统。我有代表不同类型菜单项的结构,包括那些属于子菜单的结构,以及将它们组合为通用菜单项的结构。菜单项的数组是菜单的一级。子菜单项具有指向另一个菜单项数组的指针。
问题是,子菜单条目是联合的成员,因此需要在联合之前进行定义。但是它有一个指向该联合实例的数组的指针,这会导致编译错误,因为尚未定义联合。
是否存在处理这种类型安全的方法,或者子菜单项中的指针是否必须为void *?
代码:
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;
答案 0 :(得分:4)
您需要转发声明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;
};
答案 1 :(得分:2)
声明一些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;
答案 2 :(得分:1)
问题是,子菜单条目是联合的成员,因此需要 在联合之前定义。
是的
但是它有一个指向数组的指针 联合的实例,这会导致编译错误,因为 工会尚未定义。
并不需要为您声明该类型的指针定义联合。只需声明即可。该定义可以稍后提出。
有没有一种处理这种类型安全的方法,或者我的指针在 子菜单项必须为空*?
是的。在结构定义之前先声明联合,然后再将联合定义放到后面。这确实需要您为联合类型提供一个标记,否则前向声明和后续定义将不会引用相同的类型。
示例:
typedef union entry tuEntry;
typedef struct {
// ...
tuEntry *entries[];
} ts_EntrySubmenu;
union entry
{
// ...
ts_EntrySubmenu entrySubmenu;
};
此外,我不禁注意到您的原始代码完全避免了声明任何结构或联合标记。我想确保您了解这是一个样式选择,尤其是typedef
关键字不是要定义类型,而是要声明类型的 aliases 名称。您的风格并非天生就错误,但它不支持您想做的事。您需要使用带有标签的结构和联合类型来链接同一作用域中相同类型的多个声明。