linux C編程(三)ANSI C中的類型限定詞(const/volatile/restrict)

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。    https://blog.csdn.net/u012177034/article/details/52304761
由第二節我們知道,一個變量有兩種屬性來描述,一種爲數據類型(如int,char等),一種爲存儲屬性(包括作用域,鏈接屬性,生存週期 屬性,由static和變量聲明的地方決定)。C90標準增加了兩個屬性:不變性和易變性,C99標準增加了1個屬性:restrict屬性,用於編譯器優化。 
另外,C99中規定類型限定符是冪等的,也即意味着可以在一個聲明中不止一次的使用同意限定詞,多餘的將被忽略

如下面兩種使用方式都是合理的:

const const const int n = 6;//合理

typedef const int zip;
const zip q = 8;//也是合理


本片文章着重講述這三個類型限定詞。

const限定詞
const用來限定一個變量不容許被改變。一定程度上能夠增強系統的健壯性,使得一些邏輯錯誤在編譯階段被發現。

const只讀變量&常量
const int n = 5;
int a[n];

上述代碼在使用ANSI C編譯時會出錯。原因: 
ANSI C規定數組的定義必須用常量指定大小,不能用只讀變量。雖然根據編譯過程和內存分配,這種使用是合理的(好像C++中就是合理的),但是ANSI不容許。

只讀變量和常量的區別:常量,如’abc’,’5’等不存在於內存中;只讀變量存放在內存中。 
常量可以通過宏和枚舉變量定義,字符串常量也可以在程序中定義,爲其他變量賦值,如下面的p:

char *p = "i am hungry";
p[0] = 'c';
1
2
上面的代碼在編譯時會出現內存的非法寫入錯誤,因爲”i am hungry”是一個常量,其存放在只讀存儲區,指針p指向該區域,爲p[0]賦值即像p指向的內存區域寫入是不被容許的。

const限定的內容
const的最常用法:const char m;限定m不可變(與char const m意義相等)

typedef char * pStr;
char string[4]="abc";//注意用的string[4],而不是3,因爲"abc"默認最後面跟一個'\0'字符,故大小爲4;但強制用string[3]="abc"編譯時也不會報錯
const char * p1=string;
const pStr p2 = string;
p1++;//正確
p2++;//錯誤

此例中p1定義時爲const char *p1,說明限定*p1不可變,但p1是可變的;p2的定義爲const pStr p2,說明限定的是p2不可變,因此p2++是錯誤的。(預處理時不會將pStr像宏一樣替換)

const & 指針
const修飾變量主要由兩種方式,一種是在前,一種是在後。 
(1)const在前

const int value;//value不可變
const char *pContent;//*pContent不可變
const (char *)pContent;//pContent不可變,類型爲char *
char * const pContent;//pContent不可變,類型爲char *
const char * const pContent;//pContent與*pContent都不可變

(2)const在後

int const value;//value不可變
char const *pContent;//*pContent不可變
char * const pContent;//pContent不可變
const char * pContent;//*pContent不可變
char const * const pContent;//pContent和*pContent均不可變

const & 函數
const可用來修飾:1.輸入參數 2.函數返回值 3.函數體 
如下面的三個const

const rValue func(const list_array)const;
1
1.修飾輸入參數: 
∙∙可以修飾指針傳遞的參數,避免在函數內部意外改動指針所指數據

void StringCopy(char *strDestination,char * const strSource);
1
∙∙可以修飾指針傳遞的參數,避免函數內部意外修改指針本身

void swap(int * const p1,int * const p2);
1
2.修飾函數返回值: 
∙∙修飾“指針返回值”,即指針不能被修改

//聲明
const char * getString(void);
//調用,**返回值必須加const**
const char * Str= getString();

∙∙修飾“數值返回值”

const int getNum(void);
1
volatile限定詞
volatile告訴編譯器改變量是“易變的”,即除了可能被程序改變以外還可被其他代理改變。典型的如單片機中的某些硬件外設寄存器變量,如外部中斷標誌寄存器隨時可能倍外部信號改變。 
volatile存在的目的是爲了控制程序的優化,如下面的程序:

int x;
...
val1 = x;
val2 = x;
...

本段程序中連續使用x爲val1和val2賦值,若不加valtile來限定x,則編譯器可能會在編譯的時候對這句話進行優化:第一步將x移到寄存器裏,賦值給val1,然後在繼續賦值給x2,這樣只從內存中取一次數據,效率會得到提升,但是如果x是非常容易收到其他因素變化的話,這種優化可能會產生錯誤。因此此時代碼可以寫爲如下方式,此時程序就會完全按照本來的順序執行,不會去優化與變量x相關的代碼

volatile x;
...
val1 = x;
val2 = x;

volatile可以與const同時存在,如硬件系統的時鐘,不容許軟件對其修改,因爲需設爲const;同時時鐘又是一直不斷更新的,因此需設爲volatile。

const volatile int time;
1
restrict限定詞
該限定符只適用於指針,表明該指針是訪問一個數據對象的唯一且初始的方式。該類型只能限定滿足要求(唯一且初始的訪問該數據)的指針。

int ar[10];
int *restrict restar = (int *)malloc(10*sizeof(int));//可以修飾restar,
int *par = ar;//不能修飾par,因爲par指向的ar是通過ar[10]定義的,還有很多其他種訪問的方式

一旦編譯器被告知該指針是restrict類型,編譯器就可以做一些假定,對某些代碼進行相應的優化。非restrict類型就不能做相應的優化。
--------------------- 
作者:遍地流金 
來源:CSDN 
原文:https://blog.csdn.net/u012177034/article/details/52304761 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章