民间,
考虑这段(可恶的)代码:
volatile unsigned long a[1];
unsigned long T;
void main(void)
{
a[0] = 0x6675636b; /* first access of a */
T = *a;
*(((char *)a) + 3) = 0x64; /* second access of a */
T = *a;
}
......问题:((char *)a)
是不稳定的还是非易失性的?
这引出了一个更大的问题:a的两次访问之间是否存在依赖关系?也就是说,人类的常识说有,但是C99标准说易变的东西不会混淆非易失性的东西 - 所以如果((char *)a)
是非易失性的,那么这两个访问不会混淆,没有依赖。
更准确地说,C99 6.7.3(第5段)是:
“如果尝试通过使用具有非volatile限定类型的左值来引用使用volatile限定类型定义的对象,则行为未定义。”
因此,当我们对a
进行类型转换时,volatile限定符是否适用?
答案 0 :(得分:1)
如有疑问,请运行一些代码:)我发布了一些类似的(稍微不那么可恶)测试代码(msvs 2k10中的win32 C ++应用程序)
int _tmain(int argc, _TCHAR* argv[]) {
int a = 0;
volatile int b = 0;
a = 1; //breakpoint 1
b = 2; //breakpoint 2
*(int *) &b = 0; //breakpoint 3
*(volatile int *) &b = 0; //breakpoint 4
return 0;
}
编译发布时,我可以在2和4处断点,但不能在1和3处断点。
我的结论是,类型转换决定了行为,1和3被优化了。 Intuition支持这一点 - 否则编译器必须保留列出为volatile的所有内存位置的某种类型的列表,并检查每次访问(硬,丑),而不是仅仅将其与标识符的类型相关联(更简单,更直观)
我还怀疑它是特定于编译器的(甚至可能在编译器中标记为特定标志),并且会在依赖于此行为之前在任何平台上进行测试。
实际上划伤,我只是试图不依赖于这种行为:)
另外,我知道你是专门询问数组的,但我怀疑这有什么不同。您可以轻松地为阵列添加类似的测试代码。
答案 1 :(得分:0)
volatile
说明符将要求编译器不优化该值,因为它是一个“重要”和关键值,如果由于不同的optmization机制而发生更改可能会导致问题。但这就是可以做的一切。