<?xml version="1.0" encoding="gbk"?> <rss version="2.0"><channel> <title>定阅帖子更新</title> <link>http://www.broadkey.com.cn/XML.ASP</link><description>TEAM Board - 意得法电子</description> <copyright>TEAM 2.0.5 Release</copyright><generator>TEAM Board by TEAM5.Cn Studio</generator> <ttl>30</ttl><item><link>http://www.broadkey.com.cn/Thread.asp?tid=438 </link><title>嵌入式C语言中const与volatile的用法详解</title><author>幻影</author><pubDate>2009-12-15 11:42:10</pubDate><description><![CDATA[<div>
<div style="text-align: center; line-height: 20pt; margin: 0cm 0cm 15.6pt" align="center"><strong><span style="font-size: 14pt">const</span></strong><strong><span style="font-size: 14pt">与</span></strong><strong><span style="font-size: 14pt">volatile</span></strong><strong><span style="font-size: 14pt">关键字的用法</span></strong></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">const</span><span style="font-size: 12pt">最主要的特点就是只读，有常量、常量指针，如果不是特别小心的分析</span><span style="font-size: 12pt">C</span><span style="font-size: 12pt">语言语句的书写格式，再加上指针的使用，就特别容易弄错。</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">volatile</span><span style="font-size: 12pt">关键字是一个类型修饰符，用它声明的类型变量表示可以被某些编译器未知的因素更改，比如：操作系统、硬件或者其它线程等。遇到这个关键字声明的变量，编译器对访问该变量的代码就不再进行优化，从而可以提供对特殊地址的稳定访问；如果不使用</span><span style="font-size: 12pt">valatile</span><span style="font-size: 12pt">，则编译器将对所声明的语句进行优化。之所以优化是因为访问寄存器要比访问内存单元快得多。但是优化之后容易出现问题，例如现在要直接对内存地址单元的内容修改，如果继续使用未经过</span><span style="font-size: 12pt">valatile</span><span style="font-size: 12pt">声明的变量，则读到的值有可能是寄存器中未经过修改的值，但本意是要读发生变化后的数值，所以会出现意想不到的错误。而经</span><span style="font-size: 12pt">valatile</span><span style="font-size: 12pt">声明的变量，每次访问该变量时都会从内存单元中重新读取。</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">const</span><span style="font-size: 12pt">经常用于声明不希望被其它程序修改的常量；</span><span style="font-size: 12pt">volatile</span><span style="font-size: 12pt">经常用于声明因意外而可能发生改变的变量。</span></div>
<div style="line-height: 20pt"><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp; </span><span style="font-size: 12pt">下面具体分析两个变量的用法：</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">1</span><span style="font-size: 12pt">、</span><span style="font-size: 12pt">const</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">关键字</span><span style="font-size: 12pt">const</span><span style="font-size: 12pt">有什么含意？</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">我只要一听到被面试者说：</span><span style="font-size: 12pt">&ldquo;const</span><span style="font-size: 12pt">意味着常数</span><span style="font-size: 12pt">&rdquo;</span><span style="font-size: 12pt">，我就知道我正在和一个业余者打交道。其实只要能说出</span><span style="font-size: 12pt">const</span><span style="font-size: 12pt">意味着</span><span style="font-size: 12pt">&ldquo;</span><span style="font-size: 12pt">只读</span><span style="font-size: 12pt">&rdquo;</span><span style="font-size: 12pt">就可以了。尽管这个答案不是完全的答案，但我接受它作为一个正确的答案。如果应试者能正确回答这个问题，我将问他一个附加的问题：</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">下面的声明都是什么意思？</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">const int a; </span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">int const a; </span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">const int *a; </span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">int * const a; </span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">int const * a const; </span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">前两个的作用是一样，</span><span style="font-size: 12pt">a</span><span style="font-size: 12pt">是一个常整型数；第三个意味着</span><span style="font-size: 12pt">a</span><span style="font-size: 12pt">是一个指向常整型数的指针（也就是，整型数是不可修改的，但指针可以）；第四个意思</span><span style="font-size: 12pt">a</span><span style="font-size: 12pt">是一个指向整型数的常指针（也就是说，指针指向的整型数是可以修改的，但指针是不可修改的）；最后一个意味着</span><span style="font-size: 12pt">a</span><span style="font-size: 12pt">是一个指向常整型数的常指针（也就是说，指针指向的整型数是不可修改的，同时指针也是不可修改的）。如果应试者能正确回答这些问题，那么他就给我留下了一个好印象。</span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">2</span><span style="font-size: 12pt">、</span><span style="font-size: 12pt">volatile </span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">关键字</span><span style="font-size: 12pt">volatile</span><span style="font-size: 12pt">有什么含意？并给出三个不同的例子。</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">一个定义为</span><span style="font-size: 12pt">volatile</span><span style="font-size: 12pt">的变量是说该变量可能会被意想不到地改变，这样，编译器就不会去假设该变量的值了。精确地说，优化器在用到该变量时必须每次都小心地重新读取这个变量的值，而不是使用保存在寄存器里的备份。下面是</span><span style="font-size: 12pt">volatile</span><span style="font-size: 12pt">变量的几个例子：</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">(1) </span><span style="font-size: 12pt">并行设备的硬件寄存器</span><span style="font-size: 12pt">(</span><span style="font-size: 12pt">如：状态寄存器</span><span style="font-size: 12pt">)</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">(2) </span><span style="font-size: 12pt">一个中断服务子程序中会访问到的非自动变量</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">(2) </span><span style="font-size: 12pt">多线程应用中被几个任务共享的变量</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">回答不出这个问题的人是不会被雇佣的。我认为这是区分</span><span style="font-size: 12pt">C</span><span style="font-size: 12pt">程序员和嵌入式系统程序员的最基本的问题。搞嵌入式的同志们经常同硬件、中断、</span><span style="font-size: 12pt">RTOS</span><span style="font-size: 12pt">等等打交道，所有这些都要求用到</span><span style="font-size: 12pt">volatile</span><span style="font-size: 12pt">变量。不懂得</span><span style="font-size: 12pt">volatile</span><span style="font-size: 12pt">的内容将会带来灾难。</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">假设被面试者正确地回答了这是问题（嗯，怀疑是否会是这样），我将稍微深究一下，看一下这家伙是不是直正懂得</span><span style="font-size: 12pt">volatile</span><span style="font-size: 12pt">完全的重要性。</span></div>
<div style="line-height: 20pt; text-indent: 21pt"><span style="font-size: 12pt">(1) </span><span style="font-size: 12pt">一个参数既可以是</span><span style="font-size: 12pt">const</span><span style="font-size: 12pt">还可以是</span><span style="font-size: 12pt">volatile</span><span style="font-size: 12pt">吗？解释为什么。</span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">(2) </span><span style="font-size: 12pt">一个指针可以是</span><span style="font-size: 12pt">volatile </span><span style="font-size: 12pt">吗？解释为什么。</span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">(3) </span><span style="font-size: 12pt">下面的函数有什么错误：</span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">int square(volatile int *ptr) </span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">{ </span></div>
<div style="line-height: 20pt; text-indent: 21pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">return *ptr * *ptr; </span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">}</span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">下面是答案：</span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">(1) </span><span style="font-size: 12pt">是的。一个例子是只读的状态寄存器。它是</span><span style="font-size: 12pt">volatile</span><span style="font-size: 12pt">因为它可能被意想不到地改变。它是</span><span style="font-size: 12pt">const</span><span style="font-size: 12pt">因为程序不应该试图去修改它。</span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">(2) </span><span style="font-size: 12pt">是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个</span><span style="font-size: 12pt">buffer</span><span style="font-size: 12pt">的指针时。</span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">(3) </span><span style="font-size: 12pt">这段代码有点变态。这段代码的目的是用来返回指针</span><span style="font-size: 12pt">*ptr</span><span style="font-size: 12pt">指向值的平方，但是，由于</span><span style="font-size: 12pt">*ptr</span><span style="font-size: 12pt">指向一个</span><span style="font-size: 12pt">volatile</span><span style="font-size: 12pt">型参数，编译器将产生类似下面的代码：</span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">int square(volatile int *ptr) </span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">{ </span></div>
<div style="line-height: 20pt; text-indent: 21pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">int a,b; </span></div>
<div style="line-height: 20pt; text-indent: 21pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">a = *ptr; </span></div>
<div style="line-height: 20pt; text-indent: 21pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">b = *ptr; </span></div>
<div style="line-height: 20pt; text-indent: 21pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">return a * b; </span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">} </span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">由于</span><span style="font-size: 12pt">*ptr</span><span style="font-size: 12pt">的值可能被意想不到地改变，因此</span><span style="font-size: 12pt">a</span><span style="font-size: 12pt">和</span><span style="font-size: 12pt">b</span><span style="font-size: 12pt">可能是不同的。结果，这段代码可能返不是你所期望的平方值！正确的代码如下：</span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">long square(volatile int *ptr) </span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">{ </span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">int a; </span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">a = *ptr; </span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">return a * a; </span></div>
<div style="line-height: 20pt; margin: 0cm 0cm 0pt 21pt"><span style="font-size: 12pt">}</span></div>
<div style="line-height: 20pt">&nbsp;</div>
<div style="line-height: 20pt">补充：什么是自动变量</div>
<div style="line-height: 20pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>自动变量就是指在函数内部定义使用的变量。它只允许在定义它的函数内部使用它。在函数外的其他任何地方都不能使用该变量。自动变量是局部变量，即它的区域性是在定义它的函数内部有效。当然这说明自动变量也没有链接性，因为它也不允许其它的文件访问它。由于自动变量在定义它的函数的外面的任何地方都是不可见的，所以允许我们在这个函数外的其它地方或者是其它的函数内部定义同名的变量，它们之间不会发生冲突的。因为它们都有自己的区域性，而其没有链接性(即：不允许其它的文件访问它)。</div>
</div>]]></description></item></channel></rss>