C語言(1)

static

在C語言中static關鍵字有如下的做用程序員

1,能夠用來修飾局部變量。局部變量在函數內部定義的,只有在函數內部有效(做用域),其缺省的存儲方式是動態存儲的,即指令執行到變量定義處時纔給變量分配存儲單元,函數執行結束後變量的內存單元就會被釋放掉(生命週期)。用static聲明局部變量時,則會改變變量的存儲方式,使變量成爲靜態局部變量,即在編譯時就爲變量分配內存,直到程序運行結束退出才釋放內存單元。若是在子函數中的變量,若是想要這個變量在函數執行結束後不被釋放掉,可使用static修飾。緩存

2,static修飾全局變量的時候,這個全局變量只能在本文件中訪問,不能在其它文件中訪問,即使是extern外部聲明也不能夠。函數

3,static修飾一個函數,則對函數的鏈接方式產生影響,這個函數的只能在本文件中調用,不能被其餘文件調用。這個有點相似於C#中的private。使用靜態函數的好處是,不用擔憂與其餘文件的同名函數產生干擾,另外對函數自己也是一種保護機制。性能

const

const關鍵字用來定義常量,被它修飾的變量值不能再改變。優化

const在修飾變量的時候必定要初始化,不然以後就不能再進行賦值了。3d

一,修飾指針

1,常量指針不能經過這個指針改變變量的值,可是能夠經過其餘的引用來改變變量的值。指針

/*
xutopia
*/
#include "stdio.h"

int main()
{
    int x = 6;
    const int *p;
    p = &x;
    printf("x=%d\r\n", x);
    printf("*p=%d\r\n", *p);
    x = 8;
    printf("\r\nx=%d\r\n", x);
    printf("*p=%d\r\n", *p);
    system("pause");
}

運行結果以下code

2,常量指針指向的值不能經過這個指針改變,可是常量指針能夠指向其餘的地址blog

/*
xutopia
*/
#include "stdio.h"

int main()
{
    int x = 6;
    int y = 8;
    const int *p;
    p = &x;
    printf("x=%d,y=%d\r\n", x, y);
    printf("*p=%d\r\n", *p);
    p = &y;
    printf("*p=%d\r\n", *p);
    system("pause");
}

3,指針常量是指針自己是一個常量不能夠再指向其餘地址排序

/*
xutopia
*/
#include "stdio.h"

int main()
{
    int x = 6;
    int y = 8;
    int *const p=&x;//指針常量
    printf("x=%d,y=%d\r\n", x, y);
    printf("*p=%d\r\n", *p);
    system("pause");
}

區分常量指針和指針常量的關鍵就在於 * 的位置。爲了方便記憶,把 * 讀做「指針」,把const讀做常量:

int const * x:常量指針;

int *const x:指針常量。

4,指向常量的常量指針,這種指針指向的位置不能改變,指向的值也不能改變,可是依然能夠經過其餘應用來改變。

/*
xutopia
*/
#include "stdio.h"

int main()
{
    int x = 6;
    int y = 8;
    const int* const p = &x;
    printf("x=%d,y=%d\r\n", x, y);
    printf("*p=%d\r\n", *p);
    //*p = 9;//err
    //p = &y;//err
    x = 9;
    printf("*p=%d\r\n", *p);
    system("pause");
}

二,修飾函數的參數,返回值

​ 參數參數也能夠用const來修飾,防止函數修改參數中的內容,具體特性如上訴所介紹,常量指針,指針常量,常量指針常量。函數的返回值也能夠用const來修飾,不過意義不是很大。

/*
xutopia
*/
#include "stdio.h"

const int* fun1(int param1, int* param2, const int param3, const int* param4, int *const param5,const int *const param6)
{
    printf("param1=%d\r\n", param1);
    printf("*param2=%d\r\n", *param2);
    printf("param3=%d\r\n", param3);
    printf("*param4=%d\r\n", *param4);
    printf("*param5=%d\r\n", *param5);
    printf("*param6=%d\r\n", *param6);
    
    param1 = 16;
    printf("param1=%d\r\n", param1);
    
    *param2 = 13;
    //param3 = 14;//err
    param4 = &param1;
    printf("param4=%d\r\n", *param4);
    //*param4 = 14;//err
    
    *param5 = 15;
    printf("param5=%d\r\n", *param5);
    //param5 = &param1;//err

    //param6 = &param1;//err
    //*param6 = 1;//err
    return param5;
}

int main()
{
    int a = 11, b = 12;
    int* p1, *p2;
    const int *re1;
    int *re2;
    p1 = &a;
    p2 = &b;
    re1 = fun1(1, p1, 3, p2, p2, p2);
    //re2 = fun1(1, p1, 3, p2,p2,p2);//right
    printf("\r\n*p1=%d\r\n", *p1);
    printf("*p2=%d\r\n", *p2);
    //printf("*re=%d\r\n", *re2);
    printf("*re=%d\r\n", *re1);

    system("pause");
}

三,修飾全局變量

全局變量的做用域是整個文件,若是用在其餘文件中用external聲明,那麼全局變量能夠做用到其餘的文件夾,爲了防止全局變量在使用的過程當中被不經意的修改,能夠用const修飾,這樣就能夠防止沒必要要的修改。

volatile

volatile關鍵字提醒編譯器它所定義的變量隨時均可能改變,所以編譯後的程序每次須要存儲和讀取這個變量的時候,都對直接從這個地址中讀取數據。

若是沒有volatile關鍵字,則編譯器可能優化存儲和讀取,若是這個變量由別的程序更新的話,將出現不一致的現象。若是用這個關鍵字聲明變量,編譯器對訪問該變量的代碼就再也不進行優化,從而能夠穩定地訪問特殊的地址。

簡而言之,volatile聲明的變量,就是要求程序運行的時候,每次從這個變量的地址讀取。

編譯器優化介紹:因爲內存訪問速度遠不及CPU處理速度,爲提升機器總體性能,在硬件上引入硬件高速緩存Cache(例如STM32某些型號就支持cache),加速對內存的訪問。另外在現代CPU中指令的執行並不必定嚴格按照順序執行,沒有相關性的指令能夠亂序執行,以充分利用CPU的指令流水線,提升執行速度。以上是硬件級別的優化。再看軟件一級的優化:一種是在編寫代碼時由程序員優化,另外一種是由編譯器進行優化。編譯器優化經常使用的方法有:將內存變量緩存到寄存器;調整指令順序充分利用CPU指令流水線,常見的是從新排序讀寫指令。對常規內存進行優化的時候,這些優化是透明的,並且效率很好。由編譯器優化或者硬件從新排序引發的問題的解決辦法是在從硬件(或者其餘處理器)的角度看必須以特定順序執行的操做之間設置內存屏障(memory barrier),Linux 提供了一個宏解決編譯器的執行順序問題。void Barrier(void)這個函數通知編譯器插入一個內存屏障,但對硬件無效,編譯後的代碼會把當前CPU寄存器中的全部修改過的數值存入內存,須要這些數據的時候再從新從內存中讀出。

相關文章
相關標籤/搜索