为什么在它按名称引用const结构时,不存在.rodata中的const结构数组?

时间:2016-08-15 20:03:50

标签: c++ arrays gcc struct

我有以下结构安排:

typedef struct { 
    int a;       
} Foo;

const Foo END = {0};   

const Foo table_1[] = {
    {2}, {0}           
};                     

const Foo table_2[] = {         
    {2}, END                    
};                              

基本上,我有一个结构,以及该结构的几个数组。现在,这些数组的内容永远不会改变:它们是一些在运行时使用的查找表,因此,在嵌入式环境中,我希望数据驻留在ROM中(我非常 RAM-约束,字面上争夺每几个字节)。可以想象,没有什么能阻止所有这些表驻留在ROM中(一切都是常量)。

实际上,table_1.rodata中结束(因此在启动时不会被复制到RAM中)和table_2 - 在.data中(消耗ROM和RAM) 。在反汇编目标文件时,我还可以看到一些初始化table_2的代码。

我希望所有前面提到的数组最终都在.rodata中,但看起来,只有当我“完全”写出结构初始化时才会发生这种情况(对不起,不确定,对于什么是正确的术语)这一点)。

这些初始化有什么区别?因为只有初始化是不同的 - 类型是相同的,实际数据也是相同的。它是否正在进行某种优化(想知道这里有什么优化)?有没有办法禁用它?我的意思是,我可以#define离开所有常见的表成员并完成它,但它似乎是一个黑客,而且,我真的想了解这里发生了什么。

我正在使用gcc-arm-none-eabi工具链,使用-Os构建,gcc版本为4.8.1。

1 个答案:

答案 0 :(得分:9)

gcc 5.1及以上版本执行此优化;它不是强制性的,而是由C ++标准在[basic.start.init]中考虑的:

  

3 - 允许实现使用静态存储执行非局部变量的初始化   作为静态初始化的持续时间,即使这样的初始化不需要要静态地完成,提供   该

     
      
  • 初始化的动态版本不会更改任何其他命名空间对象的值   初始化之前的范围和
  •   
  • 初始化的静态版本在初始化变量中产生相同的值   如果所有变量都不需要静态初始化,则由动态初始化产生   动态初始化。
  •   

如果您的gcc版本支持constexpr,那么标记END constexpr应该足以让它静态初始化table_2;你也可以标记table_2 constexpr以确定(同上):

  

2 - 执行常量初始化:[...]

     
      
  • 如果[...]初始化程序中出现的每个完整表达式都是一个常量表达式。
  •   

为什么我们在这里需要constexpr - 为什么const不足够?这是因为const对象仍然可以拥有mutable成员(可能是成员的成员等)并且允许在END的初始化和初始化之间进行更改table_2

struct Bar { mutable int a; };
const Bar END = {0};
int unused = ++END.a; // !!
struct Foo { int a; };
const Foo table_2[] = { {2}, {END.a} };

constexpr通常会阻止这种情况,因为[expr.const] / 2可确保在mutable对象的初始化中不能使用具有constexpr成员的复合对象。 constexpr对象仍然可以拥有自己的mutable成员,但这会阻止它用于初始化另一个constexpr对象。