首页 > 代码库 > 宏定义的用法以及再次解释const和volatile

宏定义的用法以及再次解释const和volatile

__I、 __O 、__IO是什么意思?
这是ST库里面的宏定义,定义如下:
#define     __I       volatile const        /*!< defines ‘read only‘ permissions      */
#define     __O     volatile                  /*!< defines ‘write only‘ permissions     */
#define     __IO    volatile                  /*!< defines ‘read / write‘ permissions   */

volatile和const在嵌入式设备上属于必须要掌握的知识。

const,在C语言中,不是常量,是只读变量,或者说是不能通过程序直接更改的变量,但可以间接修改。const修饰的变量,并不是不能更改的,只是不能通过程序直接修改,即,在嵌入式设备中,const修饰的寄存器,是可以通过硬件更改的。

#define     __I       volatile const 

定义的是输入口,既然是输入,证明stm32需要读取数据,而读取数据我们一般都是限制为只读属性,volatile表示这个__I修饰的寄存器是易变的。所以这里问题就来了,既然是const你还说易变,不是混乱了吗?所以才有之前介绍的,const只是我们程序不能直接修改,但是可以间接修改和被硬件修改。

#define     __O     volatile 

定义输出端口,输出用volatile修饰应该没什么争议。

#define     __IO    volatile 

定义输入输出,既要做输入也要做输出,volatile也没有什么争议。

但争议就在于st官方的注释__O为什么是只写‘write only‘?而同样用volatile修饰的__IO却备注‘read / write‘?

其实,__O,表示的是输出,输出就是写啊,有人问我,为什么不加const,例如#define    __O     volatile const  更能代表只写啊,这究其原因还是没理解const,const是只读变量,并不是不改变的常量。输出不需要只读属性就已经是只写了,因为你不能在输出的时候使用输入功能,即不能读取。

既然说到volatile,就不得不提一个经典的面试题了:  下面的函数有什么错误:

int square(volatile int *ptr)  
{   
    return *ptr * *ptr;  
}  

 这段代码有点变态。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)  
{   
    int a,b;   
    a = *ptr;  
    b = *ptr;  
    return a * b;   
}  
由于*ptr的值可能被意想不到地该变,因此ab可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)  
{   
    int a;   
    a = *ptr;  
    return a * a;   
}  

回到宏定义话题:

在阅读hal库函数或者linux内核函数时,总有人在群里问下面这种宏的用法:

1.宏定义防止 使用时错误 
用小括号包含。 
例如:#define ADD(a,b) ((a)+(b)) 
用do{}while(0)语句包含多语句防止错误 
例如:#difne DO(a,b) a+b;\ 
                   a++; 
应用时:if(….) 
                    DO(a,b); //产生错误 
            else 
                   ……
解决方法: #difne DO(a,b) do{a+b;\ 
                   a++;}while(0)

宏定义的用法以及再次解释const和volatile