相对于函数调用和返回的全局变量访问

我一直在研究这个主题,但我找不到具体的权威答案。 我希望非常熟悉C规范的人能够回答 – 即确认或驳斥我的断言,最好引用规范。

断言:如果一个程序包含多个编译单元(单独编译的源文件),编译器必须确保在调用另一个单元中的函数之前或从任何函数返回之前将全局变量(如果已修改)写入内存。 此外,在任何函数中,必须在首次使用之前读取全局。 在调用任何函数之后,不是在同一单元中,必须在使用前读取全局。 并且这些事情必须是真的,无论变量是否被限定为“volatile”,因为另一个编译单元(源文件)中的函数可以在没有编译器知识的情况下访问变量。 否则,全局变量总是需要“volatile” – 即非易失性全局变量没有任何意义。

编译器能否在同一编译单元中处理不同于未编译单元的函数? 我在全局变量上找到的“volatile”限定符的所有讨论都显示了同一编译单元中的所有函数。

编辑:编译器无法知道其他单元中的函数是否使用全局。 因此我假设上述条件。

我发现这两个问题与这个主题相关的信息,但他们没有解决它或他们提供我发现怀疑的信息:

函数调用之间是否刷新了全局变量?

我什么时候需要在ISR中使用volatile?

[..]在任何函数中,必须在首次使用之前读取全局。

当然不:

 static int variable; void foo(void) { variable = 42; } 

为什么编译器会烦恼生成代码来读取变量?

编译器必须确保在任何函数调用之前或从函数返回之前将全局变量写入内存。

不,为什么要这样?

 void bar(void) { return; } void baz(void) { variable = 42; bar(); } 

bar是一个纯函数(对于一个体面的编译器应该是可以确定的),因此在函数调用之后写入内存时不可能获得任何不同的行为。

但是,“从函数返回之前”的情况很棘手。 但是,如果我们计算内联(静态)函数,我认为一般语句(“必须”)是错误的。

编译器能否在同一编译单元中处理不同于未编译单元的函数?

是的,我认为是这样的:对于静态函数(其地址永远不会被采用),编译器确切地知道它是如何被使用的,并且该信息可用于应用一些更激进的优化。

我基于§5.1.2.3/ 6(N1570)中指定的As-If规则的C版本基于以上所有内容:

符合实施的最低要求是:

  • 根据抽象机器的规则严格评估对易失性对象的访问。

  • 在程序终止时,写入文件的所有数据应与根据抽象语义执行程序的结果相同。

  • 交互设备的输入和输出动态应按照7.21.3的规定进行。 这些要求的目的是尽快出现无缓冲或行缓冲输出,以确保在程序等待输入之前实际出现提示消息。

这是该程序的可观察行为。

特别是,您可能希望阅读以下“示例1”。