GCC 中的“空基优化”是不是可配置?

Posted

技术标签:

【中文标题】GCC 中的“空基优化”是不是可配置?【英文标题】:Is the "empty base optimization" in GCC configurable?GCC 中的“空基优化”是否可配置? 【发布时间】:2009-02-13 19:17:49 【问题描述】:

考虑这些类型:

  struct A ;
  struct B : A  int i; ;

sizeof(A) > 0 符合标准要求。

sizeof(B) 应该是 4 由于空基优化。然而在 GCC 4.1.1 上它是 5(我在这个区域使用了一包 1)。而且不一致 - 我的一些文件得到了它,有些没有。还不能确定有什么区别,我们有一个大项目。

在我使用的其他三个编译器(微软和飞思卡尔)上,我没有这个问题。根据this article,空基优化显然是可选的。

在 GCC 4.1.1 中是否有编译器选项或编译指示来调整它?我可以解决这个问题,但我想先了解发生了什么。我用谷歌搜索了一段时间,似乎找不到任何东西。

【问题讨论】:

【参考方案1】:

这总是发生。我在弄清楚之前立即发布。也许发帖的行为让我以不同的方式思考..

所以在我的问题中,示例有点过于简化了。其实更像这样:

struct Base ;
struct C1 : Base  int i; 
struct C2 : Base  C1 c; int i; 

sizeof(C1) 在所有平台上都是正确的 4,但 sizeof(C2) 在 GCC 上是 9 而不是 8。而且...显然,根据我在原始问题中链接到的文章的最后一点,GCC 是唯一正确的方法。我将在此处引用它(来自 Nathan Meyers):

根据编译器必须遵守的 ABI 规范,可以进行一系列相关的“空子对象”优化。 (几年前,Jason Merrill 向我指出了其中的一些。)例如,考虑(空)类型 A、B 和 C 的三个结构成员,以及第四个非空的结构成员。它们可以一致地占据相同的地址,只要它们彼此之间或与包含类没有任何共同的基数。 实践中的一个常见问题是让一个类的第一个(或唯一一个)成员派生自与该类相同的空基。编译器必须插入填充,以便它们两个子对象具有不同的地址。 这实际上发生在具有 interator 成员的迭代器适配器中,两者都派生自 std::iterator。一个不小心实现的标准 std::reverse_iterator 可能会出现这个问题。

所以,我看到的不一致仅发生在我有上述模式的情况下。我从空结构派生的所有其他地方都可以。

很容易解决。感谢大家的cmets和答案。

【讨论】:

英特尔编译器和 GCC 一样正确。当一个基类也是第一个成员的基类时,MSVC 过于激进并且违反了空基优化标准。我在这里为 VC++ (2005/2008) 和 GCC (4.1.1) 空基规则发布了更彻底的规则。 ***.com/questions/547290/… 这里需要进一步澄清,我可以理解这条规则“类的第一个(或唯一)成员派生自与该类相同的空基。编译器必须插入填充”以及为什么我们需要考虑空基类的子对象吗?在c1c2 中,我们只是通过继承它来取消 EB 的琐事 1 字节,对吗?【参考方案2】:

GCC C++ 使用标准填充遵循这些规则:

注意:__attribute__((__packed__)) 或更改默认打包将修改这些规则。

类 EmptyBase ; --> sizeof(EmptyBase) == 1

只要都是唯一类型(包括父级),任何数量的空基都将映射到结构偏移量中的 0。

非空基父级仅按声明的顺序排列,仅填充对齐。

如果派生类的第一个紧跟空基的成员不是从任何这些基派生的,则允许从该成员的第一个正确对齐的偏移量开始,该偏移量大于或- 等于空基地址——这可能与空基地址相同。

如果派生类中紧跟空基地址的第一个成员确实派生自这些基中的任何一个,则它将从该成员的第一个正确对齐的偏移量开始,该偏移量大于空基地址-- 这绝不是与空基地址相同的地址。

空类成员在包含类中占用至少一个字节的存储空间。


MSVC++ 遵循以下规则:

注意:#pragma pack 或更改默认打包将修改这些规则。

类 EmptyBase ; --> sizeof(EmptyBase) == 1

空基类(或从空基派生的类)从偏移量 0(零)开始的唯一方法是它是第一个基类。

非空基类将从基类的下一个有效对齐偏移量开始。

所有空基类在派生类中的有效存储空间似乎为零,并且不会影响当前偏移量,除非后面跟着另一个空基类(或从空基派生的类),在这种情况下您应该会看到以下规则。

在空基类(或从空基派生的类)之后的空基类(或从空基派生的类)将在填充到类的正确对齐方式。

最后一个基类和第一个类成员或 vft 指针之间没有填充(对齐除外)。 *** 注意:这是一种过于激进的空基优化,可能会破坏 C++ 标准。

空类成员在包含类中占用至少一个字节的存储空间。

【讨论】:

【参考方案3】:

嗯,这不是一个完整的答案,但GCC Manual 提到 g++ 有时可以将空基类放置在错误的偏移量处。请参阅有关-Wabi 选项的信息。

【讨论】:

以上是关于GCC 中的“空基优化”是不是可配置?的主要内容,如果未能解决你的问题,请参考以下文章

configure生成makefile的配置项说明

关于arm-linux-gcc已经配置好环境变量可还显示找不到的问题

在gnc gcc编译器的已配置搜索路径中找不到文件可执行文件

CodeBlocks17.12配置GNU GCC + 汉化

如何检查可配置产品是不是缺货?

Windows环境下MinGW/gcc安装和环境配置