C語言中 restrict 關鍵字學習

        restrict 是 c99 標準引入的,它只可以用於限定和約束 指針,並表明指針是訪問一個數據對象的唯一且初始的方式。即它告訴編譯器所有修改該指針所指向內存中內容的操作都必須通過該指針來修改,而不能通過其它途徑(其它變量或指針)來修改。這樣做的好處是,能幫助編譯器進行更好的優化代碼,生成更有效率的彙編代碼。如 int *restrict ptr,ptr 指向的內存單元只能被 ptr 訪問到,任何同樣指向這個內存單元的其他指針都是未定義的,直白點就是無效指針。restrict 的出現是因爲 C 語言本身固有的缺陷,C 程序員應當主動地規避這個缺陷,而編譯器也會很配合地優化你的代碼。

        考慮下面的例子:

            int ar[10];
            int *restrict restar=(int *)malloc(10 * sizeof(int));

            int *par=ar;

        這裏說明 restar 是訪問由 malloc() 分配的內存的唯一且初始的方式,但 par 就不是了。

        那麼:
           for(n = 0; n < 10; n++) {
               par[n]    += 5;
               restar[n] += 5;
               ar[n]     *= 2;
               par[n]    += 3;
               restar[n] += 3;
           }
        因爲 restar 是訪問分配的內存的唯一且初始的方式,那麼編譯器可以將上述對 restar 的操作進行優化:
           restar[n] += 8;
        而 par 並不是訪問數組 ar 的唯一方式,因此並不能進行下面的優化:
           par[n] += 8;

        因爲在 par[n] += 3 前,ar[n] *= 2 進行了改變。使用了關鍵字 restrict,編譯器就可以放心地進行優化了。


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

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

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

        如果內存存在重疊時使用 memcpy,那麼在修改 s1 指向的內存時,會覆蓋 s1 的部分內容,即不是通過 s1 指針來修改,此時加入 restrict 限制,可以避免這種情況。

  關鍵字 restrict 有兩個讀者。一個是編譯器,它告訴編譯器可以自由地做一些有關優化的假定。另一個讀者是用戶,他告訴用戶僅使用滿足 restrict要求的參數。一般,編譯器無法檢查您是否遵循了這一限制,如果您蔑視它也就是在讓自己冒險。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章