我的代码是用C语言编写的。我有一个ISR(中断服务程序),它使用全局变量与主代码通信。 ISR与主代码位于不同的编译单元中。 有什么理由我不能在主要代码中使用“volatile”,而是在ISR中使用它?
我的推理如下: volatile限定符阻止编译器完全优化ISR。从ISR的角度来看,变量不是易失性的 - 即它在ISR的持续时间内不能从外部改变,并且在ISR的持续时间内不需要输出该值。另外,如果ISR在它自己的编译单元中,编译器必须让ISR在第一次使用之前从内存中读取全局,并且它必须在返回之前存储更改。我的理由是:不需要同时编译不同的编译单元,因此编译器不知道除了ISR的范围之外发生了什么(或者它应该假装),因此它必须确保全局读取/写在ISR的边界。
或许,我误解了编译单位的意义?我发现的一个参考说GCC使这种不稳定的不匹配成为编译时错误;我不知道它怎么可能,如果它们在不同的编译单元中,它们不应该是独立的吗?我不能单独编译库函数并在以后链接它吗?Nine ways to break your systems code using volatile
也许可以从序列点的概念中得出一个论点。我不完全理解序列点或副作用的概念;但是,C99规范在5.1.2.3第2段中说明: “......在执行序列中称为序列点的某些特定点,先前评估的所有副作用都应完整,并且不会产生后续评估的副作用。”
附件C列出了包括以下内容的序列点:
价:WG14 Document: N1013, Date: 07-May-2003
注意:上一个问题Global Variable Access Relative to Function Calls and Returns询问是否在函数调用之前/之后存储/写入全局变量并返回。但这是一个不同的问题,它询问全局变量在不同的编译单元中是否可以被不同地限定为“volatile”。我使用了大部分相同的推理来证明我的初步结论,这促使一些读者认为这是同一个问题。
答案 0 :(得分:0)
ISO / IEC 9899:2011(C11标准)说:
6.7.3类型限定符
¶6如果尝试通过使用具有非const限定类型的左值来修改使用const限定类型定义的对象,则行为未定义。如果尝试通过使用具有非volatile限定类型的左值来引用使用volatile限定类型定义的对象,则行为未定义。 133)
133)这适用于行为就像使用限定类型定义的对象,即使它们实际上从未被定义为程序中的对象(例如内存映射中的对象)输入/输出地址)。
¶6的第二句说如果你有这里显示的任何一个组织你调用未定义的行为:
File main.c File isr.c:
volatile int thingamyjig = 37; extern int thingamyjig; // V1
extern int thingamyjig; volatile int thingamyjig = 37; // V2
在V1或V2的每种情况下,你都会对标准的那一部分中指定的未定义行为进行犯规 - 尽管V1是我认为你在问题中描述的。
必须始终如一地应用volatile
限定符:
File main.c File isr.c:
volatile int thingamyjig = 37; extern volatile int thingamyjig; // V3
extern volatile int thingamyjig; volatile int thingamyjig = 37; // V4
V3和V4都一致地保留了volatile限定符。
请注意,“未定义行为”的一个有效表现形式是“它表现得非常好,并且您可以按照自己的意愿行事”。不幸的是,这不是未定义行为的唯一或必然最可能的表现形式。不要冒风险。要自我保持。