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

shy*_*ent 3 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                    
};                              
Run Code Online (Sandbox Code Playgroud)

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

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

我希望所有前面提到的数组最终进入.rodata,但似乎只有在我"完全"写出结构初始化时才会发生(对不起,不确定,这是什么是正确的术语).

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

我使用gcc-arm-none-eabi工具链,搭建-Os,gcc版本是4.8.1.

eca*_*mur 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} };
Run Code Online (Sandbox Code Playgroud)

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