Chinaunix首页 | 论坛 | 博客
  • 博客访问: 17301
  • 博文数量: 7
  • 博客积分: 422
  • 博客等级: 下士
  • 技术积分: 80
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-22 16:38
文章分类
文章存档

2009年(3)

2008年(4)

我的朋友

分类: C/C++

2008-10-30 11:17:25

 在一般的教科书中,可以见到6种类型修饰符,分别是:

auto,const,register,static,volatile,extern

局 部变量除非显式指明为static,否则默认为auto,所以一般不会在代码中使用类型修饰符

auto。在后编译器时代,优化器可以合理的分配寄存器,所 以一般不会在代码中使用类型修饰符

register。extern只用于声明全局变量,用法单一。本节将主要介绍const,static和

volatile。

1. const

首先需要注意的是,const修饰的是在它前面的类型,如果它前面没有类型,那它修饰的是紧跟着它的

那个类型。例如

(a) const int i = 0;




(b) int const i = 0;


是完全一样的。在(a)中,const前面没有类型,它就修饰它后面的那个int类型。在(b)中,const

修饰它前面的int类型,两者没有任何区别。

再看另一个稍复杂一点的例子,下面两条语句却不相同:

(c) const int *pi = 0;
    /* 相当于int const *pi = 0; pi是一个指向const int的指针,复引用此运算符

       为得到一个const int的类型,该类型不能作为左值,在该语句后使用类似于*pi

       = 1的操作将导致编译错误。但该变量本身并不具备const属性,可以使用pi = &i

       的操作。可用于访问只读存储器。

    */


(d) int* const pi = 0;
    /* pi是一个指向int类型的const指针,复引用此运算符为得到一个int类型,该类型

       可以作为左值,在该语句可以使用类似于*pi = 1的操作,但该变量本身具备const

       属性,使用pi = &i的操作将导致编译错误。可用于访问固定位置的存储器。

    */


再看一个稍复杂的例子:

(e) const int* const pi = 0;
    /* pi和*pi均不能作为左值。它只适合于读取某个固定位置的只读存储器 */


const还有下列典型用法:

   * 用于参数列表,通常修饰的是指针类型,表明该函数不会试图对传入的地址进行写操作。例如:

void *memcpy(void *, const void *, size_t);


   * 用于返回值,通常是一个指向只读区域的指针。例如:

const datatype_t *get_fixed_item(int index);


   * 给固定不变的数据(例如码表)加上只读属性,在某些情况下可以减小ram的开销。


C中的指针有四种:

(1) type *p;
    /*指向变量数据的变量指针,指针的地址可以改变,其指针指向的内容也可以改变;*/



(2) type const *p;
    /*指向常量数据的变量指针,指针的地址可以改变,但其指向的内容不允许改变;*/



(3) type *const p;
    /*指向变量数据的常量指针,指针的地址不允许改变,但其指向的内容可以改变;*/



(4) type const * const p;
    /*指向常量数据的常量指针,指针的地址不允许改变,其指向的内容也不可以改变。*/



const int *p


也就是

int const *p


表示p是一个指向常整型数据的指针,该指针的地址可以改变,即可以指向其它的变量,但不能通过引

用该指针而改变其指向的内容。


2.static

     static用于全局变量声明和局部变量声明具有完全不同的语义,不得不说,这是C语言设计中

的一个不合理之处。当static用于修饰全局变量声明 (或函数声明,可以认为函数声明就是声明一个

指向代码段的指针,该指针的值最后由链接时决定,从这个意义上说,函数声明也是一种全局变量声

明),它表示该变量具有文件作用域,只能被该源文件的代码引用,不能被其他源文件中的代码访

问。在编译时引起的实际变化是被static修饰的变量不会被写入目标文件的输出节,在链接时解析

其他模块中的未定义符号时不会被引用到。它的反义词是extern。例如:


------main.c------
extern int a(void);


int main()

{

    return a();

}
------a.c------
/* link will fail unless remove “static” modifier */
static int a(void)

{

    return 0;

}


     当static用于修饰局部变量声明,它表示该变量不是分配在该函数的活动记录中,而是分配在

全局的数据段(或bss段)中。简单的说,就是被 static修饰的局部变量实际上并不是局部变量,而

是具有函数作用域的全局变量,除了只能在定义它的函数内访问外(这是由C语法决定的),它的运行时

特 征和全局变量完全一样,函数返回不会影响它的状态,它的初始化仅有一次,发生在程序的装载

时,而不是在每次函数调用的时候初始化。它的反义词是auto。

例如, 下面这段函数返回自己被调用了多少次:

int callee(void)

{
    static int times_called = 0;


    return (++ times_called);
}




3.volatile


     volatile修饰符的作用是告诉优化器不能优化这个变量的读写操作,一定要为这个变量的读写

操作生成代码。例如:


/* 延时操作 */
int foo(void)

{
    /* 100次减法后返回 */
    volatile int i = 100; /*(a)*/


    while (i > 0) i--; /*(b)*/


    return 0;
}


在无volatile修饰的情况下,因为变量i的变化对上下文无影响,所以优化器很可能会省略掉对i操

作的代码,而只生成return 0的代码,加上volatile可以保证编译器一定为语句(a)和(b)生成代

码,达到延时的目的。




/* 设备状态判定 */
int uart_write_char(int c)

{
    /* 向串口发送寄存器写入待发送字符 */
    *(volatile unsigned int *)UART_TX_REG = c;


    /* 判断是否已发送*/
    while ( (*(volatile unsigned int *)UART_STATUS_REG & TX_BIT) != 0); /*(c)*/


    return 0;
}


在语句(c)中,如果不使用volatile,优化器可能会因为在两次读取UART_STATUS_REG之间没有对

UART_STATUS_REG的写操作而将读取操作外提到循环体外而导致死循环。


http://blog.chinaunix.net/u/12325/showart.php?id=131268

http://blog.chinaunix.net/u2/77673/showart_1190102.html

阅读(1835) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~