【问题标题】:Empty structure in CC中的空结构
【发布时间】:2009-04-16 09:04:09
【问题描述】:

我有一个没有成员的结构(目前),我想知道是否可以抑制我收到的警告:

warning: struct has no members

是否可以添加一个成员并将sizeof 结构保持为零?还有其他解决方案吗?

【问题讨论】:

  • 为什么需要大小为零?
  • 因为我有一个私有接口(其中我的结构为零,因为我没有实现某些功能)和一个公共接口,其中我的一些私有结构变得不透明,只需要有和私人的一样大。
  • 我的构建系统检查私有结构大小并使用“char _opaque[SIZEOF_PRIVATE_STRUCT]”创建公共结构。

标签: c struct warnings


【解决方案1】:

在 c 中,空结构的行为取决于编译器,而 c++ 是规范的一部分 (explanations here)

C++
具有空成员序列和基类对象的类是空类。空类类型的完整对象和成员子对象应具有非零大小。

在 C 中,它相当模糊,因为 c99 标准有一些语言暗示不允许真正的空结构(请参阅 TrayMan 的回答),但许多编译器确实允许它(例如 gcc)。

由于这取决于编译器,因此在这种情况下您不太可能获得真正可移植的代码。因此,抑制警告的非便携式方式可能是您最好的选择。

【讨论】:

  • 所以没有办法避免这个警告? (否则,例如使用#ifdef 来使用特定于编译器的#pragma)
  • 此外,对于 GCC 诊断编译指示:“此外,虽然将这些编译指示放在源中的任何位置在语法上是有效的,但它们唯一支持的位置是在定义任何数据或函数之前。”这对我来说意味着我不能只取消这个警告,对吗?
  • 问题是关于 C,而不是 C++。
  • @unwesen (我指出它们之间的区别(因为许多人可能认为这是它们相同的地方)pragma 的东西与 OP 的问题有关。我的回答基本上是“这取决于编译器抱歉”,以及一些特定的编译器建议和关于 为什么 的信息
  • @claferrir - 如果你想保持结构实际上为零大小(尽管这可能不是便携无论如何的情况)抱歉
【解决方案2】:

如果您只需要结构符号来进行转换和函数参数,那么只需:

typedef struct _Interface Interface;

这将为不透明类型创建符号。

【讨论】:

  • 谢谢!我正在尝试在不同的编译器上测试我的项目,并且在 Borland C++ 中遇到了一个奇怪的编译错误。它告诉我这个使用空结构的函数不是它所声明的类的成员。在过去的 2.5 小时里,我一直在尝试解决这个问题。事实证明,我所要做的就是在声明空结构时去掉括号,就像你展示的那样,它工作正常。一个b的儿子----。谢谢!!
【解决方案3】:

从技术上讲,这甚至不是有效的 C。

TrayMan 的分析有点偏离,是的,6.2.6.1 说:

除了位域,对象由一个或多个字节的连续序列组成,其数量、顺序和编码要么明确指定,要么由实现定义。

但将其与 6.2.5-20 联系起来,即:

——结构类型描述了一个顺序分配的非空成员对象集(在某些情况下,一个不完整的数组),每个对象都有一个可选的指定名称并且可能是不同的类型。

现在您可以得出结论,结构将是一个或多个字节因为它们不能为空。您的代码向您发出警告,而相同的代码实际上会无法在 Microsoft 的 Visual Studio 上编译并出现错误:

错误 C2016:C 要求结构或联合至少有一个成员

所以简短的回答是否定的,没有可移植的方法来避免这个警告,因为它告诉你你违反了 C 标准。您必须使用编译器特定的扩展来抑制它。

【讨论】:

  • 那么在这种情况下,唯一的解决方案是使用指向 void 的指针吗? void * var; 并指向任何东西,也可以用malloc 初始化一组动态元素,这个解决方案怎么样?我已经完成了,但它使用了很多类型转换。
  • 有没有一种好方法来初始化动态元素集,它们的类型可能不同?我已经这样做了:tsk_args = malloc(2*sizeof(uint8_t)+1*sizeof(unsigned char*)); 其中tsk_args 是指向 void 的指针。
【解决方案4】:

C99 standard 对此有点模棱两可,但似乎是说空结构的大小应该不为零。

6.2.6.1 除了位域,对象由一个或多个字节的连续序列组成, 明确指定的数量、顺序和编码,或 实现定义。

【讨论】:

    【解决方案5】:
    struct zero_information { int:0; };
    

    上面的代码 sn-p 将从sizeof(struct zero_information) 产生一个-零值,但它可能会帮助您获得所需的 100% 分配给它的存储空间, 是填充(只能通过 hack 访问,尽管如果加入填充是未定义的行为,我不记得从头顶开始)。

    【讨论】:

    • 与我对 unwind 解决方案的评论相同。
    【解决方案6】:

    是否可以添加成员并保持结构的大小为零?

    不。 FWIW,C++ 允许空结构,但 sizeof() 对于空结构总是非零。

    还有其他解决方案吗?

    不容易。值得注意的是,空结构在 C 中仅受部分支持,而在 C99 中则不允许。

    C++ 支持空结构,但不同的编译器以不同的结果实现它们(对于 sizeof 和结构偏移),尤其是当您开始将继承混入其中时。

    【讨论】:

      【解决方案7】:

      如果您不需要“过于严格”的遵守,您可能会侥幸逃脱:

      struct empty {
        char nothing[0];
      };
      

      不过,这是GCC extension

      我有点希望我能够使用称为“灵活数组”的 C99 功能,声明如下:

      struct empty99
      {
        char nothing[]; // This is a C99 "flexible array".
      };
      

      但这不起作用;他们要求至少有一个普通的结构成员,他们不能是唯一的成员。

      【讨论】:

      • 好吧,GCC 无论如何都接受空结构...显然大小为 0。另一方面,如果打开了 pedantic,它将在空结构以及此解决方案上失败(pedantic warnings +把它们变成错误)。
      猜你喜欢
      • 2011-07-18
      • 1970-01-01
      • 1970-01-01
      • 2018-11-28
      • 2020-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多