volatile 和 const 若干问题

来源:互联网 发布:php会员管理系统 编辑:程序博客网 时间:2024/06/01 07:19

问题一:c语言中volatile和const可以同时修饰一个对象吗?

很多地方都说,volatile表示“易变的”,const表示"不变的,恒定的"。这两者看起来是矛盾的。

但答案是:可以的。上面的字面上的矛盾,来源于对这两个关键字含义的解释不准确。

准确的说,volatile表明对该对象的读操作都不能被编译器优化。而const表示"只读的",对const对象的显式写操作会被编译器发现并报告编译错误。

两者同时修饰一个对象的典型情况,是用于驱动中访问外部设备的只读寄存器。

网上很多解释volatile的资料,都说“表明该变量可能会被外部所改变,而这个改变是编译器所不知道的,编译器每次需要读取这个变量的时候,都直接从变量地址中读取数据”。这是对的,但是漏掉来对写操作的效果,容易让人以为volatile对写操作不起作用。

为此我做了一个小测试,明确证明volatile同样防止来编译器对写操作的优化。

int main()
{
    int a;
    a = 1;
    a = 2;
    a = 3;
    return a;
}

加上-O选项编译后的汇编代码如下:

main:
    pushl    %ebp
    movl    %esp, %ebp
    movl    $3, %eax
    popl    %ebp
    ret

可以看出来,a=1; a=2;两个赋值操作都被编译器优化掉了,甚至连变量a本身都被优化掉了。把a定义为: volatile int a再用同样的参数编译一下,得到的汇编代码如下:

main:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $16, %esp
    movl    $1, -4(%ebp)
    movl    $2, -4(%ebp)
    movl    $3, -4(%ebp)
    movl    -4(%ebp), %eax
    leave
    ret

对a的连续3次赋值操作都被保留了。

问题二:volatile和register能同时修饰一个对象吗?

答案:gcc可以接受你这样做, 但是这个register也就白加了。

问题三:volatile可以修饰结构变量吗? 可以修饰指针吗?

答案: 可以。修饰结构变量时,相当于结构体的每个成员都被volatile修饰。

修饰指针时,有两种写法,它们的效果不同。

1)volatile char * p; 或者 char volatile *p; 

    表示对*p的赋值,将全部保留不做优化。例如,*p=1; *p=2; *p=3; 编译器不会自做主张优化成*p=3;而是3个赋值操作全部保留。

    但对p的赋值操作,还是会被优化。例如,p=&a; p=&b; p=&c;编译器会只留下p=&c;

2) char * volatile p;

    这样写的话,不管是对p还是*p的赋值操作,都不会被优化掉。

问题四:如何强行突破编译器对const的保护?例如const int *p; int *m; 如何让 *p=3; 或者 m=p; 这样的操作通过编译?

可以定义一个union:

union {

    const int *a;

    int *b;

} x;

x.a = p;

m = x.b;

一切OK。

0 0
原创粉丝点击