原文:https://blog.csdn.net/qq_27312943/article/details/51273064

__I、 __O 、__IO是什么意思? 这是ST库里面的宏定义,定义如下:

1 #define     __I     volatile const          /*!< defines 'read only' permissions      */
2 #define __O volatile /*!< defines 'write only' permissions */
3 #define __IO volatile /*!< defines 'read / write' permissions */

显然,这三个宏定义都是用来替换成 volatile 和 const 的,所以我们先要了解 这两个关键字的作用:

volatile 
简单的说,就是不让编译器进行优化,即每次读取或者修改值的时候,都必须重新从内存或者寄存器中读取或者修改。

一般说来,volatile用在如下的几个地方:
1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
2、多任务环境下各任务间共享的标志应该加volatile;
3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;

我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。搞嵌入式的家伙们经常同硬件、中断、RTOS等等打交道,所有这些都要求用到 volatile变量。不懂得volatile的内容将会带来灾难。假设被面试者正确地回答了这是问题(嗯,怀疑是否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。 
1)一个参数既可以是const还可以是volatile吗?解释为什么。 
2); 一个指针可以是volatile 吗?解释为什么。 
3); 下面的函数有什么错误:

1 int square(volatile int *ptr)
2 {
3 return *ptr * *ptr;
4 }

1)是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
2); 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
3) 这段代码有点变态。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:

1 int square(volatile int *ptr)
2 {
3 int a,b;
4 a = *ptr;
5 b = *ptr;
6 return a * b;
7 }

由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:

1 long square(volatile int *ptr)
2 {
3 int a;
4 a = *ptr;
5 return a * a;
6 }

const 
只读变量,即变量保存在只读静态存储区。编译时,如何尝试修改只读变量,则编译器提示出错,就能防止误修改。 
const与define 
两者都可以用来定义常量,但是const定义时,定义了常量的类型,所以更精确一些(其实const定义的是只读变量,而不是常量)。#define只是简单的文本替换,除了可以定义常量外,还可以用来定义一些简单的函数,有点类似内置函数。const和define定义的常量可以放在头文件里面。(小注:可以多次声明,但只能定义一次)

const与指针

1 int me;
2 const int * p1=&me; //p1可变,*p1不可变 const 修饰的是 *p1,即*p1不可变
3 int * const p2=&me; //p2不可变,*p2可变 const 修饰的是 p2,即p2不可变
4 const int *const p3=&me;   //p3不可变,*p3也不可变 前一个const 修饰的是 *p3,后一个const 修饰的是p3,两者都不可变

前面介绍了 volatile 和 const 的用法,不知道大家了解了没?了解了后,下面的讲解就更加容易了: 
__I :输入口。既然是输入,那么寄存器的值就随时会外部修改,那就不能进行优化,每次都要重新从寄存器中读取。也不能写,即只读,不然就不是输入而是输出了。 
__O :输出口,也不能进行优化,不然你连续两次输出相同值,编译器认为没改变,就忽略了后面那一次输出,假如外部在两次输出中间修改了值,那就影响输出 
__IO:输入输出口,同上

为什么加下划线?

原因是:避免命名冲突 
一般宏定义都是大写,但因为这里的字母比较少,所以再添加下划线来区分。这样一般都可以避免命名冲突问题,因为很少人这样命名,这样命名的人肯定知道这些是有什么用的。 
经常写大工程时,都会发现老是命名冲突,要不是全局变量冲突,要不就是宏定义冲突,所以我们要尽量避免这些问题,不然出问题了都不知道问题在哪里。

__I、 __O 、__IO是什么意思?volatile,const 怎么用?的更多相关文章

  1. 关于STM32库中 __IO 修饰符(volatile修饰符,反复无常的意思)

    STM32例子代码中会有像这样的代码 static __IO uint32_t TimingDelay;  这里边的__IO修饰符不好理解,单从字面可以看出是为IO相关,查其标准库可以得知这个__IO ...

  2. STM32库中 __IO 修饰符(volatile修饰符)

    STM32例子代码中会有像这样的代码 static __IO uint32_t TimingDelay; 这里边的__IO修饰符不好理解,单从字面可以看出是为IO相关,查其标准库可以得知这个__IO原 ...

  3. C++ - explicit和volatile/const的内容

    第一眼见到explicit和volatile可能会一愣一愣的觉得可能是c11或者c14新加的标识符. 其实不是这样,volatile和const两个关键字在C语言的第二个版本KR C的时候就被加入了C ...

  4. __I、__O 、__IO volatile是什么?怎么用? .

    这是ST库里面的宏定义,定义如下: #define __I volatile const /*!< defines 'read only' permissions */ #define __O ...

  5. __I、 __O 、__IO是什么意思?怎么用?

    出处:http://www.chuxue123.com/forum.php?mod=viewthread&tid=122&ctid=3 __I. __O .__IO是什么意思?这是ST ...

  6. static与volatile的用法

      static 1.概述 static 声明的变量在C语言中有两方面的特征: 1).变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值.这一点是它与堆栈变量和堆变量的区别 ...

  7. C语言中的volatile——让我保持原样

    volatile译为:易变的.这不是和题目的让我保持原样矛盾了吗?其实不然,在变量前加上该关键字修饰,确实是告诉编译器,这个变量是一个容易改变的变量,不要对它进行优化,每次都要到变量的地址中去读取变量 ...

  8. const 用法总结

    在编程中我们常常会使用敞亮的概念,除了使用#define定义的宏之外,我们还有更好的选择,就是使用const关键字. 1.const关键字的意义 当我们定义一个变量,并且希望这个变量不再改变(编译器会 ...

  9. c++const小结

    C++const简单整理,本文的首次是在博客园发布的,如有错误,欢迎大家指正 博客园链接:http://www.cnblogs.com/Forever-Kenlen-Ja/p/3776991.html ...

  10. C++ const用法小结 (欢迎大家拍砖)

    C++const 关键字小结 const 是constant的缩写,本意是不变的,不易改变的意思. const 在C++中是用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数. 一.cons ...

随机推荐

  1. iOS自动化打包输出工具

    自动化打包输出工具 做开发的小伙伴有时候会接到自动化打包的需求,公司一般是要求根据一个配置文件来实现自动化配置iOS项目,比如往Xcode工程添加或修改代码.添加Framework.library.S ...

  2. 【Amadeus原创】从域副域控无法同步的解决方法

    强制同步指令:repadmin /syncall /force 同步查询:repadmin.exe /replsummary

  3. Ubuntu 20.04编译opencv-3.1.0时报错 error: 'CODEC_FLAG_GLOBAL_HEADER' was not declared in this scope

    Ubuntu 20.04源码编译安装opencv320 报错 error: 'CODEC_FLAG_GLOBAL_HEADER' was not declared in this scope的解决办法 ...

  4. 《Bootstrap4Web设计与开发实战》源代码下载

    <Bootstrap4Web设计与开发实战>源代码下载: 链接:https://pan.baidu.com/s/1GaIo390c-l-gsT6-6RaaJA 提取码:fgiq 版权声明: ...

  5. 即时通讯技术文集(第22期):IM安全相关文章(Part1) [共13篇]

    ​为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第22 期. [- 1 -] 即时通讯安全篇(一):正确地理解和使用Android端加密算法 ...

  6. 在jooq的POJO类中使用Lombok的Data注解

    jooq生成pojo类的配置根据官方给的如下: https://www.jooq.org/doc/3.14/manual/getting-started/tutorials/jooq-in-7-ste ...

  7. 三步把asp.net core 3.1应用部署到centos7

    一.编译发布Asp.net core 应用 直接使用vs2019编译发布后,通过ftp上传到centos的 /www/ 目录下,不再赘述. 二.centos安装asp.net core runtime ...

  8. Android 系统使RNDIS网卡上网

    背景说明: 一位台湾客户需要采购一批SIMCOM SIM6600CE模组用于Tinker board2s,需要适配Debain系统和Android系统. 主要修改点: 1.defconfig 增加RN ...

  9. Ubuntu Jack-server报错解决方案

    报错关键部分如下: Communication error with Jack server (35), try 'jack-diagnose' or see Jack server log 究其原因 ...

  10. java第二章数组学习

    java第二章数组 数组的概念和特点 数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个 名字命名,并通过编号的方式对这些数据进行统一管理. 特点 数组本身是引用数据类型,而数组中 ...