相对于函数调用和返回的全局变量访问 [英] Global Variable Access Relative to Function Calls and Returns

查看:136
本文介绍了相对于函数调用和返回的全局变量访问的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究这个话题,我找不到具体的权威答案。我希望有一个非常熟悉C规范的人可以回答 - 即确认或反驳我的断言,最好是引用规范。

断言:
如果程序包含多个编译单元(单独编译的源文件),编译器必须确保全局变量(如果已修改)是在任何其他单元中的功能调用之前或从任何功能返回之前写入内存。而且,在任何函数中,全局必须在第一次使用之前被读取。在调用任何函数之后,而不是在同一个单元中,必须在使用之前阅读全局函数。而且这些东西必须是真实的,无论变量是否被限定为易失性,或者因为另一个编译单元(源文件)中的函数可以在没有编译器知识的情况下访问该变量。否则,全局变量总是需要volatile - 即非易失性全局变量没有用处。

编译器能否将不同的编译单元中的函数视为不同的编译单元?我发现的所有关于globals上volatile限定符的讨论都显示了同一个编译单元中的所有函数。编辑:编译器无法知道其他单元中的函数是否使用全局函数。所以我假设上述条件。



我发现了与这个主题相关的其他两个问题,但他们没有提及它,或者提供了我认为可疑的信息:



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

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

解决方案


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


绝对不是:

 静态int变量; 
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版本:


符合要求实现如下:


  • 访问volatile对象严格按照抽象机器的规则进行评估。


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

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




这是程序的可观察行为。

特别是,您可能想阅读遵循示例1。

I have been researching this topic and I can not find a specific authoritative answer. I am hoping that someone very familiar with the C spec can answer - i.e. confirm or refute my assertion, preferably with citation to the spec.

Assertion: If a program consists of more than one compilation unit (separately compiled source file), the compiler must assure that global variables (if modified) are written to memory before any call to a function in another unit or before the return from any function. Also, in any function, the global must be read before its first use. Also after a call of any function, not in the same unit, the global must be read before use. And these things must be true whether the variable is qualified as "volatile" or not because a function in another compilation unit (source file) could access the variable without the compiler's knowledge. Otherwise, "volatile" would always be required for global variables - i.e. non-volatile globals would have no purpose.

Could the compiler treat functions in the same compilation unit differently than ones that aren't? All of the discussions I have found for the "volatile" qualifier on globals show all functions in the same compilation unit.

Edit: The compiler cannot know whether functions in other units use the global or not. Therefore I am assuming the above conditions.

I found these two other questions with information related to this topic but they don't address it head on or they give information that I find suspect:

Are global variables refreshed between function calls?

When do I need to use volatile in ISRs?

解决方案

[..] in any function, the global must be read before its first use.

Definitely not:

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

Why should the compiler bother generating code to read the variable?

The compiler must assure that global variables are written to memory before any function call or before the return from a function.

No, why should it?

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

bar is a pure function (should be determinable for a decent compiler), so there's no chance of getting any different behaviour when writing to memory after the function call.

The case of "before returning from a function" is tricky, though. But I think the general statement ("must") is false if we count inlined (static) functions, too.

Could the compiler treat functions in the same compilation unit differently than ones that aren't?

Yes, I think so: for a static function (whose address is never taken) the compiler knows exactly how it is used, and this information could be used to apply some more radical optimisations.

I'm basing all of the above on the C version of the As-If rule, specified in §5.1.2.3/6 (N1570):

The least requirements on a conforming implementation are:

  • Accesses to volatile objects are evaluated strictly according to the rules of the abstract machine.

  • At program termination, all data written into files shall be identical to the result that execution of the program according to the abstract semantics would have produced.

  • The input and output dynamics of interactive devices shall take place as specied in 7.21.3. The intent of these requirements is that unbuffered or line-buffered output appear as soon as possible, to ensure that prompting messages actually appear prior to a program waiting for input.

This is theobservable behaviorof the program.

In particular, you might want to read the following "EXAMPLE 1".

这篇关于相对于函数调用和返回的全局变量访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆