野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 41481|回复: 89

【每日一题】__I、 __O 、__IO是什么意思?怎么用?

  [复制链接]
发表于 2013-5-13 18:32:47 | 显示全部楼层 |阅读模式
Q群中总会有人会问各种不同的问题,而很多问题很适合其他人参考了,故把它粘贴上来,以供参考:


__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的值可能被意想不到地该变,因此ab可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)  
{   
    int a;   
    a = *ptr;  
    return a * a;   
}   



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

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


为什么加下划线?

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

使用道具 举报

发表于 2013-5-21 18:56:17 | 显示全部楼层
当初只是看 c primer plus 里面讲的这一块,但是没有联系到单片机寄存器这一块,所以也没有看太懂,现在还好,略懂了一些。谢谢啦。
回复 支持 反对

使用道具 举报

发表于 2013-5-21 20:20:19 | 显示全部楼层
JudeScorpio 发表于 2013-5-21 18:56
当初只是看 c primer plus 里面讲的这一块,但是没有联系到单片机寄存器这一块,所以也没有看太懂,现在还好 ...

用到才能真正的懂的……单看书,学不深
回复 支持 1 反对 0

使用道具 举报

发表于 2013-5-22 21:51:37 | 显示全部楼层
重新回忆和学习了一下,写的不错,学习了
回复 支持 反对

使用道具 举报

发表于 2013-5-23 07:59:19 | 显示全部楼层
复习一下
回复 支持 反对

使用道具 举报

发表于 2013-6-19 15:13:37 | 显示全部楼层
学习了!
回复 支持 反对

使用道具 举报

发表于 2013-8-23 09:27:47 | 显示全部楼层
const int *p=&me; *p不可变 是不是说变量me的内容也不能变了
回复 支持 反对

使用道具 举报

发表于 2013-8-23 16:56:15 | 显示全部楼层
darksnipers 发表于 2013-8-23 09:27
const int *p=&me; *p不可变 是不是说变量me的内容也不能变了

不是,是不能用 指针p 来修改 me 的内容,但可以用 me 来修改自己的内容。
const 是告诉编译器 *p 不可变罢了,编译的时候,如果检测到你 修改 *p 的值,就报错。但如果你是 me 修改,那就不报错。
回复 支持 反对

使用道具 举报

发表于 2013-8-24 11:06:09 | 显示全部楼层
格拉姆 发表于 2013-8-23 16:56
不是,是不能用 指针p 来修改 me 的内容,但可以用 me 来修改自己的内容。
const 是告诉编译器 *p 不可变 ...

明白了 谢谢真棒!!非常感谢
回复 支持 1 反对 0

使用道具 举报

发表于 2013-11-18 18:52:46 | 显示全部楼层
为什么 _O volatile 后面不加const???  _O volatile const
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-11-18 20:04:54 | 显示全部楼层
火弟 发表于 2013-11-18 18:52
为什么 _O volatile 后面不加const???  _O volatile const

弟,你来的还真勤快。

再自个想想。
回复 支持 反对

使用道具 举报

发表于 2013-11-18 21:01:01 | 显示全部楼层
fire 发表于 2013-11-18 20:04
弟,你来的还真勤快。

再自个想想。

还是哥哥好,本来看了还真不明白,现在知道了。。哈哈。。这智商真着急。。。哈哈const只读嘛。输出是写的,不去读干嘛限制只读?要是限制了,还写个屁啊 ,哈哈,,。有时候我的思维就是乱七八糟,,呜呜
回复 支持 反对

使用道具 举报

发表于 2014-1-21 09:18:26 | 显示全部楼层
谢谢 火哥 现在有点懂了! 支持!!!
回复 支持 反对

使用道具 举报

发表于 2014-1-21 09:24:34 | 显示全部楼层
火弟 发表于 2013-11-18 18:52
为什么 _O volatile 后面不加const???  _O volatile const

你好 我看了你有关IO的帖子,有个问题想请教一下 上面的定义是“#define     __I       volatile const  ”中是“___I”不是“__O” 你的问题怎么解释呢???
      
回复 支持 反对

使用道具 举报

发表于 2014-2-11 15:32:50 | 显示全部楼层
笨小鸟 发表于 2014-1-21 09:24
你好 我看了你有关IO的帖子,有个问题想请教一下 上面的定义是“#define     __I       volatile const   ...

回复的有点慢啊 _I 就是输入吗,输入当然是读了,输出_O  不需要读 人家不需要读你加const不是多次一举??
回复 支持 反对

使用道具 举报

发表于 2014-2-15 16:33:31 | 显示全部楼层
学了,理解更深了
回复 支持 反对

使用道具 举报

发表于 2014-2-16 11:12:50 | 显示全部楼层
学习了 强烈支持,非常感谢哥们
回复 支持 反对

使用道具 举报

发表于 2014-2-16 11:13:35 | 显示全部楼层
重读一次,感觉理解又加深
回复 支持 反对

使用道具 举报

发表于 2014-2-17 11:49:35 | 显示全部楼层
有点明白了
回复 支持 反对

使用道具 举报

发表于 2014-2-20 23:25:25 | 显示全部楼层
#define     __O     volatile                  /*!< defines 'write only' permissions     */
#define     __IO    volatile                  /*!< defines 'read / write' permissions   */_O和——IO都宏定义volatile,怎么说?
回复 支持 反对

使用道具 举报

发表于 2014-2-22 13:29:02 | 显示全部楼层
本帖最后由 Ω囿圉Ω 于 2014-2-22 13:31 编辑

学习了,但是
const与指针
还是没看明白,快晕死了
回复 支持 反对

使用道具 举报

发表于 2014-3-25 19:37:16 | 显示全部楼层
获益良多!!!
回复 支持 反对

使用道具 举报

发表于 2014-3-26 12:28:58 | 显示全部楼层
原来如此,学习了
回复 支持 反对

使用道具 举报

发表于 2014-5-17 16:02:50 | 显示全部楼层
略懂呀!!!!!!!!!!!!!!!!!!!!!!!!11
回复 支持 反对

使用道具 举报

发表于 2014-6-11 13:40:37 | 显示全部楼层
明白点点,在多看几遍,明白彻底
回复 支持 反对

使用道具 举报

发表于 2014-7-10 10:44:22 | 显示全部楼层
fiaa 发表于 2013-6-19 15:13
学习了!

perfect!ilike it!
回复 支持 反对

使用道具 举报

发表于 2014-7-29 20:31:58 | 显示全部楼层
强烈支持,非常感谢哥们
回复 支持 反对

使用道具 举报

发表于 2014-8-9 15:41:59 | 显示全部楼层
不错,支持!强烈支持,非常感谢哥们
回复 支持 反对

使用道具 举报

发表于 2014-8-11 11:52:08 | 显示全部楼层
火哥好给力!,我顺便把c语言也学习了
回复 支持 反对

使用道具 举报

发表于 2014-8-16 19:18:56 | 显示全部楼层
学习了。。再看几遍
回复 支持 反对

使用道具 举报

发表于 2014-8-20 20:36:25 | 显示全部楼层
学习了,火哥给力
回复 支持 反对

使用道具 举报

发表于 2014-9-17 11:49:40 | 显示全部楼层
学习了 谢谢帅呆了,赞一个
回复 支持 反对

使用道具 举报

发表于 2014-9-19 20:09:23 | 显示全部楼层
受益匪浅啊,谢谢
回复 支持 反对

使用道具 举报

发表于 2014-9-20 01:39:45 | 显示全部楼层
又长知识了。学习了。
回复 支持 反对

使用道具 举报

发表于 2014-9-20 11:22:48 | 显示全部楼层
我的疑惑跟20楼一样!希望高人老解释一下。
回复 支持 反对

使用道具 举报

发表于 2014-9-23 00:38:46 | 显示全部楼层
lzgztm521 发表于 2014-9-20 11:22
我的疑惑跟20楼一样!希望高人老解释一下。

这是在你写程序的时候 ,很好的区分 这个io口是只写, 还是即写有读
回复 支持 反对

使用道具 举报

发表于 2014-9-24 22:53:31 | 显示全部楼层
谢谢分享好的学习资料
回复 支持 反对

使用道具 举报

发表于 2014-9-25 00:12:37 | 显示全部楼层
格拉姆 发表于 2013-8-23 16:56
不是,是不能用 指针p 来修改 me 的内容,但可以用 me 来修改自己的内容。
const 是告诉编译器 *p 不可变 ...

解释的很好,谢谢
回复 支持 反对

使用道具 举报

发表于 2014-10-4 21:20:13 | 显示全部楼层
强烈支持,非常感谢哥们     看了教程很好,声音清晰,连贯。  谢谢了
回复 支持 反对

使用道具 举报

发表于 2014-10-7 21:28:49 | 显示全部楼层
可以看看这个图片 了解得更深入
捕获.PNG
回复 支持 3 反对 0

使用道具 举报

发表于 2014-10-15 10:11:35 | 显示全部楼层
真是不错,学习啦抢沙发~给哥们顶一个
回复 支持 反对

使用道具 举报

发表于 2014-10-16 11:24:46 | 显示全部楼层
“假如外部在两次输出中间修改了值,那就影响输出”,这句话是什么意思,求火哥解释。
回复 支持 反对

使用道具 举报

发表于 2014-11-5 20:31:03 | 显示全部楼层
原来如此啊   
回复 支持 反对

使用道具 举报

发表于 2014-11-21 11:08:51 | 显示全部楼层
不错了
回复

使用道具 举报

发表于 2014-11-21 21:09:35 | 显示全部楼层
不错哦!!!
回复

使用道具 举报

发表于 2014-11-23 16:37:34 | 显示全部楼层
笔试的时候很受益,大家记住啊
回复 支持 反对

使用道具 举报

发表于 2014-11-28 15:48:30 | 显示全部楼层
学习重在应用啊,不用永远也不知道
回复 支持 反对

使用道具 举报

发表于 2014-12-4 11:12:37 | 显示全部楼层
同样和20楼的疑问,_I和_IO怎么说呢?希望高人来解释一下啊?
回复 支持 反对

使用道具 举报

发表于 2014-12-27 10:46:55 | 显示全部楼层
抱火哥大腿大腿腿
回复 支持 反对

使用道具 举报

发表于 2015-1-7 15:42:22 | 显示全部楼层
恍然大悟!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-11-24 08:00 , Processed in 0.055965 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表