<address id="ousso"></address>
<form id="ousso"><track id="ousso"><big id="ousso"></big></track></form>
  1. C語言

    C語言關鍵字RESTRICT介紹

    時間:2025-01-20 19:17:33 美云 C語言 我要投稿
    • 相關推薦

    C語言關鍵字RESTRICT介紹

      學習C語言也有好長時間了,相信大家在學習C語言的過程中也都有所收獲,不過,也應該遇到了許多問題。今天小編在這里就幫同學們介紹一下怎么了解restrict這個詞。

      C語言關鍵字RESTRICT介紹

      要理解 restrict,先要知道什么是 Pointer aliasing。

      Pointer aliasing 是指兩個或以上的指針指向同一數據,例如

      int i = 0;

      int *a = &i;

      int *b = &i;

      這樣會有什么問題呢?

      如果編譯器采用最安全的假設,即不理會兩個指針會否指向同一數據,那么通過指針讀寫數據是很直觀的。

      然而,這種假設會令編譯器無法優化,例如:

      int foo(int *a, int *b)

      {

      *a = 5;

      *b = 6;

      return *a + *b; // 不一定是 11!

      }

      如果 a 和 b 都指向同一數據,*b = 6 會導致 *a = 6,返回12。所以編譯器在做 *a + *b 的時候,需要重新讀取 *a 指向的數據:

      foo:

      movl $5, (%rdi) # 存儲 5 至 *a

      movl $6, (%rsi) # 存儲 6 至 *b

      movl (%rdi), %eax # 重新讀取 *a (因為有可能被上一行指令造成改變)

      addl $6, %eax # 加上 6

      ret

      如果我們確保兩個指針不指向同一數據,就可以用 restrict 修飾指針類型:

      int rfoo(int *restrict a, int *restrict b)

      {

      *a = 5;

      *b = 6;

      return *a + *b;

      }

      編譯器就可以根據這個信息,做出優化:

      rfoo:

      movl $11, %eax # 在編譯期已計算出 11

      movl $5, (%rdi) # 存儲 5 至 *a

      movl $6, (%rsi) # 存儲 6 至 *b

      ret

      但如果用了 restrict 去修飾兩個指針,而它們在作用域內又指向同一地址,那么是未定義行為。

      總括而言,restrict 是為了告訴編譯器額外信息(兩個指針不指向同一數據),從而生成更優化的機器碼。注意,編譯器是無法自行在編譯期檢測兩個指針是否 alias。如使用 restrict,程序員也要遵守契約才能得出正確的代碼(指針不能指向相同數據)。

      以個人經驗而言,編寫代碼時通常會忽略 pointer aliasing 的問題。更常見是在性能剖測時,通過反編譯看到很多冗余的讀取指令,才會想到加入 restrict 關鍵字來提升性能。

      RESTRICT簡介

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

      RESTRICT應用

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

      void * memcpy(void * restrict s1, const void * restrict s2,size_tn);

      void * memmove(void * s1, const void * s2,size_tn);

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

      關鍵字restrict有兩個讀者。一個是編譯器,它告訴編譯器可以自由地做一些有關優化的假定。另一個讀者是用戶,他告訴用戶僅使用滿足restrict要求的參數。一般,編譯器無法檢查您是否遵循了這一限制,如果您蔑視它也就是在讓自己冒險。

    【C語言關鍵字RESTRICT介紹】相關文章:

    C語言關鍵字05-09

    C語言關鍵字及其解釋06-01

    C語言關鍵字有哪些02-28

    c語言的關鍵字有哪些06-15

    C語言關鍵字const用法03-16

    C語言的關鍵字define的使用08-03

    C語言關鍵字const的使用05-23

    C語言的關鍵字enum的使用04-28

    C語言的關鍵字知識要點04-21

    <address id="ousso"></address>
    <form id="ousso"><track id="ousso"><big id="ousso"></big></track></form>
    1. 日日做夜狠狠爱欧美黑人