_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 的,所以我们先要了解 这两个关键字的作用:

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

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

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

1)是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
    2); 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
    3) 这段代码有点变态。这段代码的目的是用来返指针*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;   
}

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

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

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

为什么加下划线?

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

=========================狡猾的分割线=================================================================

  volatile一般用在以下三个方面:

  1、中断标志位

  2、多线程共享的变量

  3、状态寄存器(也就是楼主所说的定义的内部的绝对地址):

    绝对地址的话 要加 Volatile,不然肯定会被编译系统优化掉。
    相对地址或普通内存,看用户的定义。
    有时候, Volatile 也伴随着 __no_init 一起,特别是在定义硬件内部绝对地址的时候。

  4、空等待


  如volatile int i;
  for(i=0;i<1000;i++);

  如果不加volatile,很可能被编译器当做无效代码删除掉。

转载于:https://www.cnblogs.com/kalo1111/p/3239287.html

嵌入式 c 中结构体经常碰到_I、 __O 、__IO是什么意思?相关推荐

  1. 嵌入式开发过程中结构体字节对齐问题pragma pack(1)

    一.引言 曾经刚入门嵌入式在开发一个应用时,用到了自定义结构体,底层嵌入式单片机运行该结构体没问题,但是在Qt开发应用软件对接协议时,一直通不过,仔细分析才发现是QT这边的结构体字节并没有按照单字节对 ...

  2. 1006.c++中结构体赋值碰到的bug

    在项目调试过程中,碰到 一个这样的问题,c++结构体赋值问题.在c语言中,一个结构体变量是可以赋值给另外一个结构体变量的.在c++情况有所变化,仅此记录一下. 此为一个概率事件. //定义接收数据数据 ...

  3. C语言定义了一个结构体怎么分配内存?C\C++中结构体变量与结构体指针内存分配问题?

    C语言定义了一个结构体怎么分配内存?C\C++中结构体变量与结构体指针内存分配问题? 问题1:结构体指针最开始怎么分配内存?用sizeof()是不能确定大小的. 问题2:给结构体变量分配之后,是否还要 ...

  4. C 语言中结构体强制转换--实验

    2019独角兽企业重金招聘Python工程师标准>>> 对于C语言中结构体强制转换做了如下实验, 或许可以解惑一些问题 对于结构体, 我理解的属性有: 成员的顺序, 成员的类型,成员 ...

  5. c#中结构体和类的比较

    前几天,有位同学问我它们用起来有什么区别,当时也不大清楚,糊弄过去了,但是,人不能自欺欺人,不能连自己的无知也要糊弄! 翻了下书,总结一下. 区别: 结构是一种用关键字struct声明的自定义数据类型 ...

  6. c++中结构体套结构体用 = {0}初始化编译报错解决办法(用memset或者={})(error: invalid conversion)

    我这有个结构体: VENC_CHN_ATTR_S venc_chn_attr; /* the attribute of the venc chnl*/ typedef struct rkVENC_CH ...

  7. C中结构体的存储分配

    对于C语言中结构体所占的存储空间的大小,也一直是笔试面试的常客,今天好好看了一下这方面,以前一直以为很清楚了,今天通过各种实际测试举例,发现原来还是没有搞透彻,好在现在是彻底懂了,所以和大家分享,希望 ...

  8. swift string转int_swift中结构体和类的区别(值类型和引用类型的区别)

    在swift中结构体和类有着更多的相同之处,在一般的使用中能够做到互相替换.我们可以先看看官方文档的描述: Unlike other programming languages, Swift does ...

  9. C#中结构体定义并转换字节数组

    ref: https://www.cnblogs.com/dafanjoy/p/7818126.html C#中结构体定义并转换字节数组 最近的项目在做socket通信报文解析的时候,用到了结构体与字 ...

  10. java发送c语言结构体_C语言中结构体直接赋值?

    在C语言中结构体变量之间可以进行赋值操作吗? 简单结构体的赋值 先说结论:一般来说,C语言中的结构体变量可以用另一个变量对其进行赋值或初始化.简单结构体(不包含指针成员)直接赋值没有问题. 我们先下面 ...

最新文章

  1. 如何提高ORACLE数据库的查询统计速度
  2. python自学教程读书导图-自学Python第一天:起点读书自动领取经验值(附思路讲解)...
  3. 用3ds导入spk文件好小坐标多_2020东莞长安贴片厂代工代料哪家好-鸿鑫辉
  4. GraphPad Prism 的统计显著性报告中*或**或**的含义是什么?
  5. boost::graph模块实现包含平均测地线示例
  6. 2020 年,React.js 开发者如何更好地修炼内功?
  7. ipv6地址_「案例」路由器怎么自动获取IPv6地址?
  8. 如何实现大数据可视化系统
  9. 自旋锁、排队自旋锁、MCS锁、CLH锁
  10. GEO数据库中platform信息详解
  11. 疯狂java 视频_疯狂Java讲义配书视频教程 下载
  12. 显卡功耗测试用什么软件,显卡功耗测试_AMD显卡_显卡评测-中关村在线
  13. cobar php,cobar配置安装_MySQL
  14. 机器学习从入门到创业手记-2.算法与导师
  15. 黑苹果成功引导到安装界面,USB鼠标无法使用的解决办法
  16. 2021-2027中国工业机械电动执行器市场现状研究分析与发展前景预测报告
  17. 什么是对称正定矩阵?
  18. Android适配器以及作用,Android Studio:自定义Adapter(适配器)的一些通俗易懂的理解(以一个简单的聊天界面为例)...
  19. 无人机无线Mesh自组网,CV5200远距离WiFi模组,实时通信传输技术
  20. PaddleOCR车牌检测识别训练、部署

热门文章

  1. 深入分析Windows和Linux动态库应用异同
  2. 给定一个数组,寻找次大的数 (1)
  3. 一次CDN源站负载高的问题排查及解决
  4. 数据采集之登录那些事
  5. DevExpress v18.1新版亮点——WPF篇(一)
  6. C# 操作offfice权限问题
  7. python if __name__ == ' __main__'
  8. 17.企业应用架构模式 --- 会话状态模式
  9. 6.深入分布式缓存:从原理到实践 --- Memcached 周边技术
  10. 61.Linux/Unix 系统编程手册(下) -- SOCKET: 高级主题