为什么常量结构数组在按名称引用常量结构时不放在 .rodata 中?
Why isn't array of const structs placed in .rodata when it references a const struct by name?
我有以下结构的安排:
typedef struct {
int a;
} Foo;
const Foo END = {0};
const Foo table_1[] = {
{2}, {0}
};
const Foo table_2[] = {
{2}, END
};
基本上,我有一个结构体,以及该结构体的几个数组。现在,这些数组的内容永远不会改变:它们是一些查找表,在运行时使用,因此,在嵌入式环境中,我希望这些数据驻留在ROM中(我非常 ram约束,字面上为每几个字节而战)。可以想象,没有什么可以阻止所有这些表驻留在ROM中(所有表都是const)。
实际上,table_1
最终在.rodata
中(因此它在启动期间不会被复制到RAM中),table_2
-在.data
中(消耗ROM和RAM)。当反汇编目标文件时,我还可以看到一些初始化table_2
的代码。
我希望所有上述数组结束在.rodata
,但它似乎只会发生,如果我写出结构的初始化"完整"(对不起,不确定,这是什么正确的术语)。
这些初始化的区别是什么?因为只有初始化不同,类型是相同的,实际数据也是相同的。它是否正在进行某种优化(不知道这里优化了什么)?有办法让它失效吗?我的意思是,我可以通过#define
删除所有常见的表成员并完成它,但这看起来像是一个hack,而且,我真的很想了解这里发生了什么。
我正在使用gcc-arm-none-eabi工具链,使用-Os
构建,gcc版本为4.8.1。
gcc 5.1及以上版本执行此优化;在[basic.start.init]:
中,它不是强制的,但由c++标准考虑。3 - 允许使用静态存储执行非局部变量的初始化duration作为静态初始化,即使这种初始化不需要静态地完成
- 初始化的动态版本不会改变命名空间中任何其他对象的值
- 初始化的静态版本在初始化的变量中产生相同的值如果所有不需要静态初始化的变量都被初始化,则由动态初始化生成动态初始化。
如果你的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. cn]const]/2确保具有mutable
成员的复合对象不能用于constexpr
对象的初始化。constexpr
对象仍然可以拥有自己的mutable
成员,但这会阻止它被用来初始化另一个constexpr
对象。
假设是c++。
table_2
的初始化不是c++标准中的常量表达式。常量表达式是所有不具有左值到右值转换(使用END
时具有这种转换)的内容,除非左值(END
):
- 具有整型或枚举类型,并引用完整的非易失性
使用常量表达式初始化const对象。
END
既不是整型也不是enum。
- 是指向字符串元素的非易失性全局值文字
END
不是字符串字面值。
- 具有文字类型,并引用使用constexpr定义的非易失性对象或其不可变的子对象
END
没有被constexpr定义。
- 具有文字类型,并引用一个非易失性对象,该对象的生存期开始于该表达式
的求值。
END
的生命周期没有在table_2
的评估范围内开始。
因此编译器别无选择,只能将table_2
初始化从静态上下文中移开。如果你用constexpr
声明END
,我想条件3就满足了,你最终会得到rodata
中所有的东西。
c++标准的相关文本在[expr]中。
- 为什么"具有常量成员的结构"类型的指针不能指向"具有非常量成员的结构"?
- 调用 cout 时如何在结构中输出常量文本?
- 返回对常量结构(指针类型)成员的引用:明显的左值到右值转换
- 将结构C++成员从非常量转换为常量
- 列出常量和数组结构字段的初始化
- 如何初始化具有常量变量的结构数组
- c++ 是否提供了一种使整个结构常量(不可修改)的方法?
- ARM C++编译器不会编译具有可变常量成员的结构
- 为什么常量静态变量应该在结构中初始化?
- CPP/C 中的常量用法和结构构造函数中的澄清
- 常量结构的指针成员
- 结构中的常量成员即使在初始化后也返回 0
- 结构初始化中的常量正确性
- 如何将常量中的值设置为结构 c++ 中
- 如何在C++中声明静态常量结构
- 结构内工会的常量成员的问题
- 如何在 C++11 中创建结构的编译时常量实例
- C++常量结构成员初始化
- C++:结构、运算符"new"和常量
- 使结构体在 C 中常量