【问题标题】:How can a union member have a pointer to an instance of the union?联合成员如何拥有指向联合实例的指针?
【发布时间】:2019-02-27 15:11:37
【问题描述】:

我可能过于复杂了..

我正在尝试用 C on Arduino 为嵌入式应用程序制作一个可重复使用的分层菜单系统。我有结构来表示不同类型的菜单项,包括那些是子菜单的,以及这些的联合作为通用菜单项。菜单条目数组是菜单的一个级别。一个子菜单项有一个指向另一个菜单项数组的指针。

问题是,子菜单项是联合体的成员,所以需要在联合体之前定义。但是它有一个指向这个联合的实例数组的指针,这会导致编译错误,因为联合尚未定义。

是否有一种类型安全的方式来处理这个问题,或者我在子菜单条目中的指针是否必须是 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;

【问题讨论】:

    标签: c pointers arduino


    【解决方案1】:

    您需要转发声明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;
    };
    

    【讨论】:

    • 我认为有一些机制可以做到这一点,但是当我尝试使用您的消息中的剪切和粘贴再次尝试时,我收到编译错误“错误:冲突声明'typedef union tuEntry tuEntry'"
    • @CraigGraham 您只使用一次typedef。当您稍后定义联合时,您只需定义它而不使用 typedef。
    【解决方案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;
    

    【讨论】:

      【解决方案3】:

      问题是,子菜单项是联合体的成员,所以需要 在联合之前定义。

      是的。

      但它有一个指向数组的指针 这个联合的实例,这会导致编译错误,因为 union 尚未定义。

      不需要为您定义联合来声明指向该类型的指针。它只需要被声明。定义可以稍后来。

      有没有一种类型安全的方式来处理这个问题,或者我的指针在 子菜单条目必须是 void*?

      是的。在结构定义之前前向声明联合,然后将联合定义放在后面。这确实需要您为联合类型提供标签,否则前向声明和后续定义将不会引用同一类型。

      例子:

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

      此外,我不禁注意到您的原始代码完全避免声明任何结构或联合标记。我想确保您了解这是一个样式选择,尤其是typedef 关键字不是关于定义类型,而是关于为类型名称声明别名。你的风格本身并没有错,但它不支持你想做的事情。您需要使用带标签的结构和联合类型来链接同一范围内相同类型的多个声明。

      【讨论】:

        猜你喜欢
        • 2019-10-11
        • 1970-01-01
        • 2015-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多