【问题标题】:How to define a struct in a struct and reuse the same name twice?如何在一个结构中定义一个结构并重复使用相同的名称两次?
【发布时间】:2021-03-03 21:09:25
【问题描述】:

我有一个简单的 C 代码示例,在 struct 中使用 struct

  • 我需要文档 (doxygen) 一个 named 结构,在我的示例中为 HermannS
  • doxygen 中,我可以使用 \ref ottoS::HermannS::age 引用 age
  • doxygen 中我可以使用\ref ottoS.name.age
  • 对于逻辑,名称 HermannS 必须相同。

问题:但是现在代码创建了一个redefinition-error

struct ottoS {
  struct HermannS {
    int age;
  } name;
};

struct otherS {
  struct HermannS {
    int size;
  } name;
};

int main ()
{
  return 0;
}

我收到以下错误消息:

main.c:16:10: error: redefinition of ‘struct HermannS’
   struct HermannS {
          ^~~~~~~~
main.c:10:10: note: originally defined here
   struct HermannS {
          ^~~~~~~~

问题:如何在struct 中定义struct 并重用名称HermannS

更好的问题:是否有一个 gcc 扩展(前缀)来隐藏这个错误? → 但是对于一个简单的 doxygen 文档问题,这将是一个非常的代价。

【问题讨论】:

  • 对于逻辑,HermannS 的名称必须相同 - 对于什么逻辑? C 中没有(有效的)代码我可以想象出于任何原因需要内部结构的名称标签(也许除了一些预处理器魔法)
  • 正如我所提到的,它是 doxygen 要求 named 结构使用 @987654333 引用变量 age @
  • @AndreasOtto 文档应该匹配代码,而不是相反。没有可能的代码可以使您拥有的代码有效。
  • @AndreasOtto:C 不能支持你在 doxygen 中尝试做的事情——你必须重新考虑你的文档方法。
  • @ThomasJager 事实上,文档驱动编程并不是一个坏方法。只是在这种情况下,文档似乎被过度指定而无法实施。

标签: c struct compiler-errors doxygen naming


【解决方案1】:

struct 声明不会像在 C++ 中那样在 C 中创建新的命名空间,因此您不能创建对 struct 类型“本地”的类型名称。标签名HermannS只能用于一种struct类型定义。

C 有四个命名空间:

  • 所有标签(由:goto 消除歧义);
  • 所有标签名称(由structunionenum 消除歧义)
  • 成员名称(由.-> 消除歧义)
  • 所有其他名称(typedef 名称、枚举常量、变量名称、函数名称等)

不幸的是,您尝试执行的操作在 C 中不起作用 - 您必须为每个内部结构定义使用不同的标记名称。

【讨论】:

    【解决方案2】:

    你不能,正如编译器告诉你的那样,你也真的不需要。如果您没有在其他任何地方使用该结构,请不要命名它:

    struct ottoS {
      struct {
        int age;
      } name;
    };
    
    struct otherS {
      struct {
        int size;
      } name;
    };
    

    唯一的其他(明显)解决方案是对两个内部结构进行不同的命名。

    如果您的逻辑/代码/文档基于您需要这两个不同结构具有相同名称的事实,那么我建议重新审视该逻辑,因为它看起来有缺陷。

    是否有 gcc 扩展(前缀)来隐藏此错误?

    不,没有。这不是一个简单的错误,它是无效的 C 代码:您实际上是在同一名称下定义了两种不同的类型。除非您避免这种情况,否则编译器将无法编译您的代码。

    【讨论】:

    • 对于doxygen 我需要内部struct 的名称 → 这就是重点。
    • @AndreasOtto 好吧,你不能拥有它。要么不使用名称,要么使用两个不同的名称
    【解决方案3】:

    C 标准在第 6.7.2.1 节第 8 节中说

    结构声明列表的存在 struct-or-union-specifier 在翻译中声明一个新类型 单位。

    因此,同一翻译单元中的 所有 结构共享相同的命名空间。 HermannS 被重新定义,因此代码格式错误。

    一些解决方法是添加带有父结构名称的前缀:

    struct ottoS {
      struct ottoS_HermannS {
        int age;
      } name;
    };
    
    struct otherS {
      struct otherS_HermannS {
        int size;
      } name;
    };
    

    最新的 C 标准允许实现接受来自扩展集的字符,例如 $。这将有助于避免与更传统的名称发生冲突。它适用于 gcc。但是,代码将不再是可移植的。

    struct ottoS {
      struct ottoS$HermannS {
        int age;
      } name;
    };
    
    struct otherS {
      struct otherS$HermannS {
        int size;
      } name;
    };
    

    它有点模仿 C++ 中的 :: 运算符。您可以使用其他一些 unicode 字符并使用它使用类似 sed 的工具对 Doxygen 文档进行后处理。我的意思是用::替换魔术字符。

    【讨论】:

    • 使用$等一直是实现定义的
    • @MM,感谢您指出这一点。题主使用的是GCC,这里可以使用$
    【解决方案4】:

    由于程序格式不正确,因此无法编译。但是,如果除了声明之外从未使用过struct HermannS,那么您可以使用以下技巧。

    如果HermannS 被删除,那么ottoS.nameotherS.name 将成为匿名结构,代码将被编译。所有匿名结构都是独立的类型。只需将-DHermannS= 传递给 GCC 的命令即可。

    gcc prog.c -DHermannS=
    

    它将添加一个宏HermannS,该宏扩展为一个空标记。

    不要将此选项传递给 doxygen 以使其生成正确的文档。

    【讨论】:

      猜你喜欢
      • 2022-01-02
      • 2020-08-07
      • 2017-06-16
      • 2011-06-22
      • 2015-05-24
      • 2021-07-22
      • 2020-04-29
      • 2014-11-30
      • 1970-01-01
      相关资源
      最近更新 更多