1. 程式人生 > 其它 >C限定符

C限定符

const

用const關鍵字宣告的變數,其值不能通過賦值或遞增、遞減來修改。

const變數只能宣告同時初始化。

    float val = 10;
    const float * pf;  // pf 指向一個float型別的const值,可以指向其他值,但不能通過pf修改所指的值

    // pt是一個const指標,不能指向其他值,但是它所指的值可以修改。 
    // const指標必須在宣告時初始化
    float * const pt = &val;    
    pf = &val;
    // pointer既不能指向其他值也不能修改其指的值
    const float * const pointer = &val;

volatile

volatile限定符告知計算機,代理(不是變數所在的程式)可以改變變數的值。通常他被用於硬體地址以及在其他程式或同時允許的執行緒中共享資料。
volatile設計編譯器的優化。

val1 = x;
val2 = x; // 智慧的編譯器會注意到程式碼使用了兩次x,但併為改變它的值,於是編譯器把x的值臨時儲存在暫存器中,提高訪問速度。
// 如果一些其他代理在以上兩條語句之間改變了x的值,就不能這樣優化。
// 如果沒有volatile關鍵字,編譯器不知道這種事情會發生,
// 如果宣告中沒有volatile關鍵字,編譯器會假定變數的值在使用過程中不變,然後再嘗試優化程式碼
const volatile int *ploc;
volatile const int lod;
// volatile和const同時限定一個值,設定為程式不能更改的變數,但是可以通過代理改變
// volatile和const的順序不重要

restrict

restrict關鍵字允許編譯器優化某部分程式碼以更好的支援計算。
只能用於指標,表明該指標是訪問資料物件的唯一且初始的方式。

int ar[10];
int * restrict restar = (int*) malloc(10*sizeof(int));
int * par;
// restar 是訪問malloc分配的記憶體的唯一且初始的方式

for( int n=0;n<10;n++)
{
  par[n] += 5;
  restar[n]+=5;
  ar[n]*=2;
  par[n]+=3;
  restar[n]+=3;
}
// 如果把restar[n]+=5 和restar[n]+=3替換為restar[n]+=8,效果相同
// 但如果把par[n]+=5和par[n]+=3替換為par[n]+=8,將導致計算錯誤
// 因為par不是訪問其執行的資料的唯一訪問方式,兩次par相關語句之間用ar改變了資料的值

上例中如果使用了restrict關鍵字,編譯器就可以選擇捷徑優化計算,比如可能選擇用restar[n]+=8,
但如果沒用,編譯器會假設最壞的情況,即兩次使用指標之間,存在其他識別符號可能改變了資料。

restrict也可以用於函式形參,表明其他識別符號不會修改指標指向的資料。

void * memcpy(void * restrict s1, const void * restrict s2, size_t n);
// restrict關鍵字表示s1和s2都是訪問相應資料的唯一方式
void memove(void * s1, const vodi * s2, size_t n);

restrict 關鍵字有兩個作用:

  1. 告訴編譯器這是唯一訪問資料的方式,可以採取一些優化方案
  2. 告訴使用者要使用滿足restrict要求的引數

_Atomic

表示相應變數上的操作是原子型別的

_Atomic int hogs;  // hogs是一個原子型別的變數

關鍵字的新位置

void ofmouth(int * const a1, int * restrict a2, int n);  // 舊風格
void ofmouth(int a1[const], int a2[restrict], int n);  // c99新風格

// static 引入了新的用法,處理表明變數是靜態變數外,還可以告訴編譯器如何使用形式引數
double stick(double ar[static 20])
// 函式呼叫中的實際引數應該是一個指向陣列首元素的指標,且陣列至少有20個元素
// 讓編譯器使用這些資訊優化函式編碼