出处:http://www.chuxue123.com/forum.php?mod=viewthread&tid=122&ctid=3

__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:输入输出口,同上

为什么加下划线?

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

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

  1. static与volatile的用法

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

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

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

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

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

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

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

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

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

  6. asp.net webform 当前上下文中不存在名称“__o”

    错误 CS0103 当前上下文中不存在名称“__o” 最近在搞一个webform项目, 再页面写了点<%%>代码, 结果编译下居然出现了这个错误 炸裂啊,  这是什么毛线, 看起来是 In ...

  7. ARM中 __IO的作用解析

    __IO在头文件中预定义 #define __IO volatile volatile 影响编译器编译的结果, 指出:volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要 ...

  8. 关于STM32 __IO 的变量定义

    这个_IO 是指静态 这个 _IO 是指静态 volatile uint32_t 是指32位的无符号整形变量uint32_t 是指32位的无符号整形变量: 搞stm32这么久了,经常看到stm32里面 ...

  9. [蓝牙] 5、Battery Service module

    Detailed Description This module implements the Battery Service with the Battery Level characteristi ...

随机推荐

  1. Layerui 弹出层的位置设置

    距顶 offset: '300px' 例1: layer.msg("请先选择项!", { offset: '300px' });例2: layer.confirm("确定 ...

  2. 第一个spring boot应用

    前提 首先要确保已经安装了java和maven: $ java -version java version "1.8.0_102" Java(TM) SE Runtime Envi ...

  3. chineseocr项目的配置阶段出现的问题及解决方案

    chineseocr为GitHub上的一个开源项目,主要使用yolos,crnn等深度学习框架训练好后的模型使用.测试结果发现,不管是针对文本文件.表格文件.还是场景图,如身份证火车票,识别效果都比较 ...

  4. OOM排除与JVM调优

    仅先记录,后续整理 1. 常用命令: jstat gcutil jmap 2. 打印GC执行情况: 通过执行jinfo -flag +PrintGCDetails <pid>直接动态开启, ...

  5. 教你使用Python制作酷炫二维码

    这篇文章讲的是如何利用python制作狂拽酷炫吊炸天的二维码,非常有趣哦! 可能你见过的二维码大多长这样: 普普通通,平平凡凡,没什么特色... 但,如果二维码长这样呢! 或者 这样! 是不是炒鸡好看 ...

  6. 洛谷 - P4567 - 文本编辑器 - 无旋Treap

    https://www.luogu.org/problem/P4567 事实证明无旋Treap是不是不可能会比Splay快? #include<bits/stdc++.h> using n ...

  7. python实现一个简单的网络聊天程序

    一.Linux Socket 1.Linux Socke基本上就是BSD Socket(伯克利套接字) 伯克利套接字的应用编程接口(API)是采用C语言的进程间通信的库,经常用在计算机网络间的通信.B ...

  8. OtterTune配置记录

    0. 准备两台Ubuntu 18.04的虚拟机,安装mysql(供server-side存储调优数据用)和postgresql(供client-side存储业务数据用,这里以PostgreSQL为例. ...

  9. C# String的几种比较方法对比(Compare,CompareTo, CompareOrdinal、Equals)

    原文:http://blog.csdn.net/wushang923/article/details/7527499 注意点:切换方法的时候要注意返回值引起的变化!!! 1.Compare会通过传递进 ...

  10. C++ 编译器的安装(MinGW)

    GNU GNU是一个自由软件工程项目,GNU工程已经开发了一个被称为“GNU”(GNU是“不是UNIX”的缩写)的.对Unix向上兼容的完整的自由软件系统(free software system). ...