c99標準的restrict關鍵字

參考自restrict程序員

restrict解釋

restrict關鍵字出現於C99標準,wiki上的解釋restrict from wiki編程

In the C programming language, as of the C99 standard, restrict is a keyword that can be used in pointer declarations. The restrict keyword is a declaration of intent given by the programmer to the compiler. It says that for the lifetime of the pointer, only the pointer itself or a value directly derived from it (such as pointer + 1) will be used to access the object to which it points. This limits the effects of pointer aliasing, aiding optimizations. If the declaration of intent is not followed and the object is accessed by an independent pointer, this will result in undefined behavior. The use of the restrict keyword in C, in principle, allows non-obtuse C to achieve the same performance as the same program written in Fortran.[1]緩存

在C編程語言中,從C99標準開始,restrict是一個能夠在指針聲明中使用的關鍵字。restrict關鍵字是由程序員給編譯器的一種意向聲明。它表示在指針的生命週期內,只有指針自己或直接從指針派生的值(如指針+ 1)將用於訪問指針指向的對象。這限制了指針別名的效果,有助於優化。若是沒遵循指針聲明的意圖,使用不受約束的指針對其指向對象存取,將致使結果是未定義的。編程語言

實例

上面這堆翻譯好像我只看懂了:restrict關鍵字用於指針的聲明。那到底什麼意思呢?在進一步瞭解restrict以前,須要瞭解什麼是pointer aliasing
pointer aliasing是指多個指針指向同一塊內存區域,例如:函數

int a = 10;
int* ptr1 = &a;
int* ptr2 = &a;

則ptr一、ptr2互稱對方爲本身的pointer aliasing。考慮下面這個函數:優化

int foo(int* a, int* b)
{
    *a = 2;
    *b = 3;
    return *a + *b;
}

通常狀況下,編譯器翻譯出來的彙編代碼會相似(以ARM彙編爲例):this

01    str     r0, [fp, #-8]         @傳遞參數指針a
02    str     r1, [fp, #-12]            @傳遞參數指針b
03    ldr     r3, [fp, #-8]         @獲得指針a
04    mov     r2, #2
05    str     r2, [r3]              @*a = 2;
06    ldr     r3, [fp, #-12]            @獲得指針b
07    mov     r2, #3
08    str     r2, [r3]              @*b = 3;
09    ldr     r3, [fp, #-8]         @獲得指針a      
10    ldr     r2, [r3]              @r2 = *a,     重讀*a,由於若是a==b,則08行會覆蓋05行的賦值!!!!!
11    ldr     r3, [fp, #-12]            @獲得指針b
12    ldr     r3, [r3]              @r3 = *b;
13    add     r0, r2, r3            @*a + *b;

若是咱們能夠提早告訴編譯器a != b,則編譯器能夠優化出更簡潔的彙編(假設a、b指針都是非volatile的):編碼

01    str     r0, [fp, #-8]         @傳遞參數指針a
02    str     r1, [fp, #-12]            @傳遞參數指針b
03    ldr     r3, [fp, #-8]         @獲得指針a
04    mov     r2, #2
05    str     r2, [r3]              @*a = 2;
06    ldr     r3, [fp, #-12]            @獲得指針b
07    mov     r1, #3
08    str     r1, [r3]              @*b = 3;
09    add     r0, r1, r2            @*a + *b;

比上面少了4條指令。爲何呢?由於上面那段彙編中得考慮一種狀況,若是指針a == b,那麼第08行的指針賦值會覆蓋05行的指針賦值,爲了保險起見,*a + *b就得從新從內存中取值,才能獲得正確的結果。若是咱們顯式的告訴編譯器a != b,則編譯器就會使用寄存器裏面的緩存數據來優化代碼。如何顯式告訴編譯器呢?就是用restrict關鍵字來修飾指針。翻譯

注意事項

可是有點須要注意,不是說用restrict修飾指針後就保證了指針不會出現pointer aliasing,這種保證由程序員本身編碼時確保。就是說程序員本身保證對同一內存區域的引用只有一個指針指向,而後經過restrict修飾此指針變量,在開啓編譯優化後,編譯器將會特別留意被restrict修飾的指針,進行優化。指針

restrict關鍵字只能修飾object類型的指針(例如int restrict *pfloat (* restrict foo)(void)都是錯誤的用法)。restrict僅用於修飾左值(lvalue)。例如使用它強制轉換指針或者修飾函數返回值都是錯誤的用法。

解釋下2個名詞:
object:
在C語言中,對象是執行環境中的數據存儲區域,其內容能夠表示值(當解釋爲具備特定類型時,值是對象內容的含義)。每一個對象有以下特徵:

  • 尺寸(能用sizeof計算)
  • 有對齊需求
  • 存儲期(automatic, static, allocated, thread-local)
  • 有效類型
  • 值(多是不肯定的)
  • 可選地,表示此對象的標識符(就是變量名)

int restrict *p 修飾的不是指針。
float (* restrict foo)(void),foo指針指向的區域明顯不具有存儲數據的能力,*foo = 12是非法的,由於若是它是一個函數指針,指向的內存區域是隻讀的。

左值(lvalue):
只能出如今C語言賦值表達式左邊的。
顯然ret = fun()、a = (int)b就說明了函數返回值,強轉都是屬於右值。

相關文章
相關標籤/搜索