在启用优化的情况下,GCC未报告结构存储大小错误

时间:2015-05-06 14:59:20

标签: c gcc struct compiler-optimization

在文件struct_test.c中我写道:

static struct x x; 

我用GCC编译(4.8.2,Ubuntu)

gcc -c -O0 struct_test.c

我得到了可以理解的错误:

error: storage size of 'x' isn't known

然后我重新编译,这次启用了优化

gcc -c -O struct_test.c

并且编译文件时没有错误。

我可以理解为什么启用优化会删除错误,但有人可以帮助我获取实际的编译器选项,指示gcc忽略未定义的标记' x'?

1 个答案:

答案 0 :(得分:4)

当它出现在文件范围时,此代码:

static struct x x;

x声明为struct x类型的对象并具有内部链接。之前不需要声明struct x类型:

  

如果形式struct-or-union identifier的类型说明符不是[在结构类型声明中],并且标识符的其他声明都不可见,那么它声明了一个不完整的结构或联合类型,并且将标识符声明为该类型的标记。

(C99 6.7.2.3/8)

在翻译单元中首次遇到时不完整的结构或联合类型仍然可以在该翻译单元中稍后完成:

  

未知内容的结构或联合类型[...]是不完整类型。对于该类型的所有声明,通过在稍后的同一范围内声明相同的结构或联合标记及其定义内容,它已完成。

(C99 6.2.5 / 22)

C通常区分“声明”,它指定对象的类型,和“定义”,它们都指定类型并导致要保留的存储。在给定的翻译单元中,非定义的声明可能具有在该单元内从未完成的不完整类型。

C99的第6.9.2节规定了哪些文件范围对象声明是定义:

  • 具有文件范围的声明和初始化程序是一个定义(具体地说,“外部定义”,即使它定义的对象可能具有内部链接)
  • 具有文件范围且没有初始化程序的声明,并且具有静态存储类或没有存储类说明符是“暂定定义”。如果翻译单元不包含同一对象的外部定义,则行为就好像存在具有初始化程序0的外部定义。

本节还规定“如果对象的标识符声明是暂定定义并且具有内部链接,则声明的类型不应是不完整的类型。”这适用于此,但由于翻译单元中某一点处不完整的类型可以通过稍后的声明来完成,因此它本身并不会使所讨论的代码行无效。但是,它 使仅包含该行的翻译单元无效。

那么GCC有什么用呢?

由于作为完整翻译单元的代码违反了“不应该”的语言约束,因此会产生未定义的行为。 GCC没有义务拒绝代码或产生任何类型的诊断,但允许其中一种或两种都做。事实证明,无论优化级别如何,gcc都会在启用-Wall-pedantic标记时发出有关代码的警告。无论如何,gcc明确拒绝成为验证代码标准合规性的工具。

然而,这种特殊的违规行为相对温和。因为永远不会引用该对象,所以gcc可以假装它甚至从未声明过而不会冒错误或意外行为。

-fdce(死代码消除)选项似乎是影响此特定行为的选项。奇怪的是,虽然-fdce足以抑制优化级别O0的错误,但-fno-dce并未将其恢复到更高的优化级别。