提问者:小点点

数组和类型转换的易失性的含义


各位,

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

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;
}

...问题:((字符*)a)是易失性的还是非易失性的?

这就引出了一个更大的问题:a的两个访问之间应该存在依赖关系吗?也就是说,人类常识说有,但 C99 标准说易失性事物不会别名非易失性事物 - 所以如果 ((char *)a) 是非易失性的,那么这两个访问不会别名,并且没有依赖关系。

更准确地说,C99 6.7.3(第5段)的内容是:

如果试图通过使用具有非易失性限定类型的左值来引用用易失性限定类型定义的对象,则行为是未定义的

那么,当我们类型转换 a 时,易失性限定符是否适用?


共2个答案

匿名用户

有疑问时,运行一些代码:)我制作了一些类似的(稍微不那么可恶的)测试代码(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被优化掉了。直觉支持这一点——否则编译器将不得不保存某种类型的所有内存位置的列表,列为易失性的,并检查每一次访问(硬的,难看的),而不是仅仅将它与标识符的类型相关联(更容易和更直观)。

我还怀疑它是特定于编译器的(即使在编译器中也可能特定于标志),并且在依赖此行为之前会在任何平台上进行测试。

实际上,我会尽量不依赖这种行为:)

另外,我知道您专门询问了数组,但我怀疑这有什么不同。您可以轻松地为数组编写类似的测试代码。

匿名用户

就像你说的,它是“未定义的”。也就是说恶魔可以从你的鼻子里出来。请尽可能坚持“定义”的行为。< code>volatile说明符将要求编译器不要优化该值,因为它是一个“重要”和关键的值,如果由于不同的优化机制而改变,可能会导致问题。但它能做的也就这些了。