• 关于C语言的类型修饰符


     分享网址

    http://wenku.baidu.com/link?url=e-xWNn7f84rrEf_vhHz5CQh2LCVmaGBTA6iB0BC8zPv_8eXz5SKmRofsSuenh8wn_JjeQZBD103xCA6wqDkYo9SzlIvKgCpYwwrbyNvbxVS

     

    在一般的

    C

    教科书中,可以见到

    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

    的开销。

     

     

     

     

    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_RE 

    G

    之间没有对

    UART_STATUS_REG

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

  • 相关阅读:
    POJ3683 Priest John's Busiest Day
    POJ3678 Katu Puzzle
    洛谷4782 【模板】2-SAT 问题
    BZOJ2330或洛谷3275 [SCOI2011]糖果
    POJ1236或洛谷2746或洛谷2812 Network of Schools
    POJ2230 Watchcow
    POJ2942 Knights of the Round Table
    POJ3694 Network
    BZOJ1123或洛谷3469 [POI2008]BLO-Blockade
    animition动画的加入
  • 原文地址:https://www.cnblogs.com/DMDD/p/4994941.html
Copyright © 2020-2023  润新知