宏定义的用法以及再次解释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的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
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)

时间: 2024-12-12 10:47:24

宏定义的用法以及再次解释const和volatile的相关文章

C语言宏定义#define用法

#define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用该命令,使得程序的运行与预期的目的不一致,或者在读别人写的程序时,把运行结果理解错误,这对 C语言的学习很不利.1 #define命令剖析1.1   #define的概念#define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本.

宏定义(#define)和常量(const)的区别

最近开始准备一边做实验室的研究,一边记录一些遇到的编程中的小知识点.今天在测试对矩阵进行SVD分解时,需要定义矩阵的行和列的大小,我习惯性的用宏定义来定义了这两个变量,在运行的时候,就开始思考宏定义和常量之间有些什么样的分别. 参考了一些别人的说法,自己在这里做一个小小的总结. 类型和安全检查不同 宏定义是字符替换,没有数据类型的区别,同时这种替换没有类型安全检查,可能产生边际效应等错误: const常量是常量的声明,有类型区别,需要在编译阶段进行类型检查 编译器处理不同 宏定义是一个“编译时”

宏定义 #define 和常量 const 的区别

宏定义 #define 和常量 const 的区别 类型和安全检查不同 宏定义是字符替换,没有数据类型的区别,同时这种替换没有类型安全检查,可能产生边际效应等错误: const常量是常量的声明,有类型区别,需要在编译阶段进行类型检查 编译器处理不同 宏定义是一个"编译时"概念,在预处理阶段展开,不能对宏定义进行调试,生命周期结束与编译时期: const常量是一个"运行时"概念,在程序运行使用,类似于一个只读行数据 存储方式不同 宏定义是直接替换,不会分配内存,存储与

C/C++中const关键字的用法及其与宏定义的比较

1.const关键字的性质 简单来说:const关键字修饰的变量具有常属性. 即它所修饰的变量不能被修改. 2.修饰局部变量 1 const int a = 10; 2 int const b = 20; 这两种写法是等价的,都是表示变量的值不能被改变,需要注意的是,用const修饰变量时,一定要给变量初始化,否则之后就不能再进行赋值了,而且编译器也不允许不赋初值的写法: 在C++中不赋初值的表达一写出来,编译器即报错,且编译不通过. 在C中不赋初值的表达写出来时不报错,编译时只有警告,编译可以

const和宏定义的区别!!!

宏的命名规范:一般以项目前缀开头,key结尾. #开头表编译. 宏的用法:1.定义常用字符串. 2.定义一段代码. const与宏的区别:1.编译时刻:宏-预编译    const-command+b(编译阶段)编译. 2.宏不会检查代码错误,只是替换,但是const会编译报错. 3.宏的好处:定义代码或字符串.方法.参数 const不能.  坏处:使用大量宏,容易造成编译时间久,每次都需要重新替换. const作用:限制类型 1.const仅仅用来修饰右边的变量(基本数据变量p,指针变量*p)

const基础知识、const在C++和C中的异同、const与#define宏定义的异同

1.const基础知识 (1)用const定义常量 const int a = 5;   //定义了一个int型常量a,其值为5 (注:在C++中将其存储在符号表中(key,value),并不分配内存空间,只有在取地址或者定义为全局变量在其他文件中使用时才分配内存空间) (2)const与指针 1 const int* p1 = &a; //p1是指向常量a的指针,a的值不能通过指针p1改变 2 3 int* const p2 =&b; //p2是只能指向b的指针,b的值可以通过p2改变

C++中宏的定义与用法(现已被内联函数所代替)

在noip中,宏还是被经常采用,所以这里讲一下,C++中宏的定义与用法 第一种用法——配合条件编译:#define DEBUG 定义一个叫DEBUG的标识符.它应该与#ifdef或#ifndef配合使用.举例如下: #define DEBUG #ifdef DEBUG void print(int v) { cout << v << endl;} #else void print(int) {} #endif 如果符号DEBUG存在,那么编译器会编译上面的.能输出数值的print,

iOS define 宏定义 和 const定义常量区别

const   const 是c++中的修饰符.  c++中常用来定义常量,修饰左值. #define 宏定义语句, 在预处理阶段直接做文本替换,不做类型检查. 它们之间的最大区别: 1.  对于const 变量,系统只给了一个相应的内存地址,而#define则是给出了一个立即数.因为const变量是存放在内存的静态区域中,所以在程序运行过程中const变量只有一个拷贝,而#define 所定义的宏变量却有多个拷贝,所以宏在程序运行过程中所消耗的内存要比const变量的大得多.#define所定

宏定义、const变量、枚举的区别

1.宏定义是在预处理阶段进行展开:cnost变量是在编译运行阶段使用 2.宏定义没有类型,不做任何类型检查,仅仅是进行展开:const修饰的变量具有具体的类型,编译阶段执行检查 3.宏定义在文件中有多少次就展开多少次,不会分配内存空间:const修饰的变量会在内存中分配空间 1.枚举属于常量:但宏定义不是常量 2.枚举常量是实体的一种:但宏定义不是实体 3.枚举具有类型,但宏定义没有类型,枚举与普通变量有作用域和值,但宏定义没有,它是一种预处理替换