如何在结构中定义结构并重复使用相同的名称两次?

How to define a struct in a struct and reuse the same name twice?

我有一个简单的 C 代码示例,在 struct.

中使用 struct

问题:但是现在代码创建了一个重定义错误

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 文档问题来说,这是一个非常 high 的代价。

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

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

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

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

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

is there a gcc extension (prefix) to hide this error?

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

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

C 有四个名称空间:

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

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

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

The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit.

所以所有 同一个翻译单元中的结构共享同一个命名空间。 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 文档进行后处理。我的意思是用 ::.

替换魔法字符

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

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

gcc prog.c -DHermannS=

它将添加一个扩展为空标记的宏 HermannS

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