restrict關鍵字

值得注意的是,一旦你決定使用restrict來修飾指針,你必須得保證它們之間不會互相重疊,編譯器不會替你檢查。程序員

關鍵字restrict有兩個讀者。一個是編譯器,它告訴編譯器能夠自由地作一些有關優化的假定。另外一個讀者是用戶,他告訴用戶僅使用知足restrict要求的參數。通常,編譯器沒法檢查您是否遵循了這一限制,若是您蔑視它也就是在讓本身冒險。less

使用restrict的好處是,能幫助編譯器進行更好的優化代碼,生成更有效率的彙編代碼ide

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 it 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 caching optimizations. If the declaration of intent is not followed and the object is accessed by an independent pointer, this will result in undefined behavior.函數

 

Optimization優化優化

If the compiler knows that there is only one pointer to a memory block, it can produce better code. For instance:this

void updatePtrs(size_t *ptrA, size_t *ptrB, size_t *val)指針

{rest

  *ptrA += *val;code

  *ptrB += *val;orm

}

In the above code, the pointers ptrA, ptrB, and val might refer to the same memory location, so the compiler will generate less optimal code :

load R1 ← *val ; Load the value of val pointer

load R2 ← *ptrA ; Load the value of ptrA pointer

add R2 += R1 ; Perform Addition

set R2 → *ptrA ; Update the value of ptrA pointer

; Similarly for ptrB, note that val is loaded twice,

; because ptrA may be equal to val.

load R1 ← *val

load R2 ← *ptrB

add R2 += R1

set R2 → *ptrB

However if the restrict keyword is used and the above function is declared as :

void updatePtrs(size_t *restrict ptrA, size_t *restrict ptrB, size_t *restrict val);

then the compiler is allowed to assume that ptrA, ptrB, and val point to different locations and updating one pointer will not affect the other pointers. The programmer, not the compiler, is responsible for ensuring that the pointers do not point to identical locations.

Now the compiler can generate better code as follows:

load R1 ← *val

load R2 ← *ptrA

add R2 += R1

set R2 → *ptrA

; Note that val is not reloaded,

; because the compiler knows it is unchanged

load R2 ← *ptrB

add R2 += R1

set R2 → *ptrB

Note that the above assembly code is shorter because val is loaded once.

 

例子1

C庫中有兩個函數能夠從一個位置把字節複製到另外一個位置。在C99標準下,它們的原型以下:

void * memcpy(void * restrict s1, const void * restrict s2, size_t n);

void * memove(void * s1, const void * s2, size_t n);

這兩個函數均從s2指向的位置複製n字節數據到s1指向的位置,且均返回s1的值。二者之間的差異由關鍵字restrict形成,即memcpy()能夠假定兩個內存區域沒有重疊。memmove()函數則不作這個假定,所以,複製過程相似於首先將全部字節複製到一個臨時緩衝區,而後再複製到最終目的地。若是兩個區域存在重疊時使用memcpy()會怎樣?其行爲是不可預知的,既能夠正常工做,也可能失敗。所以,使用memcpy()時,您必須確保沒有重疊區域。這是程序員的任務的一部分。

 

例子2

#include<stdio.h>

 

int main(void)

{

    int a = 5;

    int * restrict ptr = &a;

    ++a;

    *ptr += 8;

    int *p = &a;

    ++(*p);

 

    printf("%d\n", a);

 

    return 0;

}

編譯命令  gcc  -std=c99   test.c   // 編譯和運行都OK,but never這樣幹,這就違背了// restrict的用意。它主要用來修飾函數指針參數和由malloc獲得的指針。

restrict是C99中新增的關鍵字,在C89和C++中都不支持,在gcc中能夠經過-std=c99來獲得對它的支持。

相關文章
相關標籤/搜索