数组和类型转换的volatile的含义

时间:2012-11-02 16:31:02

标签: c arrays casting volatile

民间,

考虑这段(可恶的)代码:

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限定符是否适用?

2 个答案:

答案 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机制而发生更改可能会导致问题。但这就是可以做的一切。