C编译器有义务总是从内存中重新加载常量值吗?

C编译器有义务总是从内存中重新加载常量值吗?,c,C,我的嵌入式C程序中有一个const变量。它在程序代码中定义并初始化为0。它通过链接器脚本放置在一个特殊的ROM区域。可以通过特殊编程过程更改特殊区域的内容,但在主程序执行期间不能更改 问题是我是否必须将常量声明为volatile。如果它没有标记为volatile,编译器是否允许用0替换对它的所有引用?或者在程序执行过程中,它必须至少加载一次吗?如果标记为volatile,编译器必须在每次需要它的值时从内存中加载它 如果未标记为volatile,编译器可以从内存加载一次,将其存储在寄存器中,并使用

我的嵌入式C程序中有一个
const
变量。它在程序代码中定义并初始化为
0
。它通过链接器脚本放置在一个特殊的ROM区域。可以通过特殊编程过程更改特殊区域的内容,但在主程序执行期间不能更改


问题是我是否必须将常量声明为
volatile
。如果它没有标记为
volatile
,编译器是否允许用
0
替换对它的所有引用?或者在程序执行过程中,它必须至少加载一次吗?

如果标记为
volatile
,编译器必须在每次需要它的值时从内存中加载它

如果未标记为
volatile
,编译器可以从内存加载一次,将其存储在寄存器中,并使用此寄存器,而不是再次加载

一个不优化的编译器可以做到这一点,但它也可能愚蠢地每次都加载它。(因为不重新加载实际上本身就是一种优化。)


优化编译器可能会注意到
常量
,并决定可以使用它的实际文本值来编译它;直到程序的
.data
部分中根本不显示原始常数为止。(或者可能是这样,但它永远不会被“阅读”。)


由于更改了链接器脚本中的值,编译器无法“知道”编译后更改的值。在这种情况下,请使用
volatile
:告诉编译器在编译时不要相信该值是已知的唯一方法。

看起来您的变量实际上是一个常量(即在程序执行期间不会更改),其值是编译器未知的。如果是这种情况,您可以这样声明:

extern const int variable;
(即,没有
volatile
且没有初始值设定项)并让链接器脚本或其他工具设置正确的值


然后,编译器将被允许加载它,并可能永远将其保留在寄存器中,但在编译时不能用0或任何其他值替换它。

为什么要告诉编译器它是常量,而不是常量?使它成为
常量
,这正是volatile的作用。@EdHeal
const
并不意味着“它不会改变”。它的意思是“它不会通过这个变量改变”。如果它在程序运行期间不能改变,你可以声明它
extern const
(没有
volatile
)并省略一个初始值设定项。
const volatile
的意思是“我不会改变这个值,但其他线程/进程可能会改变。”当进程/线程运行时,变量是否可以通过外部方式更改,代码是否必须知道当前值?然后使其
易失性
。否则,只需
const
就可以了。“优化编译器可能会注意到该const,并决定可以使用它的实际文本值来编译它”;这根本不是
const
的意思。如果没有答案所提供的上下文,你的措辞就会产生误导,让人们相信
const
的意思不仅仅是“如果你通过这个左值修改底层对象,编译器会抱怨”。请注意,这是关于C最难理解的神话之一,“C是可移植程序集”,“内联的
意味着编译器肯定会在任何地方内联函数”,以及
sizeof(int)*CHAR\u BIT==32
@Rhymoid:
const
的含义不止这些。例如,C11最终草案,“如果试图通过使用具有非常量限定类型的左值来修改使用常量限定类型定义的对象,则行为是未定义的。”@Rhymoid“这根本不是常量的意思”,它本身不是
const
的意思,而是与“仿佛”规则相结合,这就是它对优化编译器的
const
意义。注意@ RADLISUS没有说这是必然发生的。@ JordanMelo不是C++语义的规则部分,不是C语义的一部分?这是一个好的建议,但是我必须绑定到代码中定义的const,并通过链接器脚本放置在ROM CurrCurty中。我的问题来了——我是否必须使用volatile?如果你真的需要在C中定义变量,那么制作一个单独的源文件,其中只包含
const int variable=0
,将其与所有其他代码分开编译,并将其链接到中。“我被绑定到解决方案”我不确定为什么这被称为“解决方案”而不是“问题”。但不管是什么,如果没有其他问题,您必须使用
volatile