begränsa

I programmeringsspråket C är restrict ett nyckelord , introducerat av C99-standarden , som kan användas i pekardeklarationer . Genom att lägga till denna typ qualifier , tipsar en programmerare till kompilatorn att under pekarens livstid kommer ingen annan pekare att användas för att komma åt objektet som den pekar på. Detta gör att kompilatorn kan göra optimeringar (till exempel vektorisering) som annars inte skulle ha varit möjliga.

begränsa begränsar effekterna av pekaraliasing , vilket hjälper till med optimeringar . Om avsiktsförklaringen inte följs och objektet nås av en oberoende pekare kommer detta att resultera i odefinierat beteende .

Optimering

Om kompilatorn vet att det bara finns en pekare till ett minnesblock kan den producera bättre optimerad kod. Till exempel:

      

    
    
 void  updatePtrs  (  size_t  *  ptrA  ,  size_t  *  ptrB  ,  size_t  *  val  )  {  *  ptrA  +=  *  val  ;  *  ptrB  +=  *  val  ;  } 

kan pekarna ptrA , ptrB och val referera till samma minnesplats , så kompilatorn kan generera mindre optimal kod:


       
       
       
       
       
       
   
   ; Hypotetisk RISC-maskin.   ldr  r12  ,  [  val  ]  ; Ladda minne vid val till r12.   ldr  r3  ,  [  ptrA  ]  ; Ladda minne vid ptrA till r3.   lägg till  r3  ,  r3  ,  r12  ; Utför addition: r3 = r3 + r12.   str  r3  ,  [  ptrA  ]  ; Lagra r3 på minnesplatsen ptrA, uppdatera värdet.   ldr  r3  ,  [  ptrB  ]  ; 'load' kan behöva vänta tills föregående 'store' är klar.   ldr  r12  ,  [  val  ]  ; Måste ladda en andra gång för att säkerställa konsistens.   lägg till  r3  ,  r3  ,  r12  str  r3  ,  [  ptrB  ] 

Men om nyckelordet restrict används och ovanstående funktion deklareras som

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

då tillåts kompilatorn att anta att ptrA , ptrB och val pekar på olika platser och att uppdatera minnesplatsen som refereras av en pekare kommer inte att påverka minnesplatserna som refereras av de andra pekarna. Programmeraren, inte kompilatorn, är ansvarig för att se till att pekarna inte pekar på identiska platser. Kompilatorn kan t.ex. ordna om koden, först ladda alla minnesplatser, sedan utföra operationerna innan resultaten skickas tillbaka till minnet.

    
    
  
   
   
    
   ldr  r12  ,  [  val  ]  ; Observera att val nu bara laddas en gång.   ldr  r3  ,  [  ptrA  ]  ; Dessutom, alla 'belastningar' i början ...   ldr  r4  ,  [  ptrB  ]  lägg till  r3  ,  r3  ,  r12  lägg till  r4  ,  r4  ,  r12  str  r3  ,  [  ptrA  ]  ; ... alla 'butiker' till slut.   str  r4  ,  [  ptrB  ] 

Ovanstående monteringskod är kortare eftersom val endast laddas en gång. Dessutom, eftersom kompilatorn kan ordna om koden mer fritt, kan kompilatorn generera kod som körs snabbare. I den andra versionen av exemplet ovan sker alla lagringsoperationer efter laddningsoperationerna , vilket säkerställer att processorn inte behöver blockera mitt i koden för att vänta tills lagringsoperationerna är klara.

Observera att den verkligt genererade koden kan ha olika beteenden. Fördelen med ovanstående mini-exempel tenderar att vara liten, och i verkliga fall tenderar stora slingor som gör tung minnesåtkomst att vara det som verkligen underlättas av begränsa.

Som nämnts ovan, hur felaktig kod beter sig är odefinierat , kompilatorn säkerställer bara att den genererade koden fungerar korrekt om koden följer avsiktsförklaringen.

Stöd av C++-kompilatorer

C++ har inte standardstöd för restrict , men många kompilatorer har motsvarigheter som vanligtvis fungerar i både C++ och C, såsom GCC :s och Clang :s __restrict__ och Visual C++ :s __declspec(restrict) . Dessutom stöds __restrict av dessa tre kompilatorer. Den exakta tolkningen av dessa alternativa sökord varierar beroende på kompilatorn:

  • I kompilatorer i Unix-stil som GCC och Clang betyder __restrict och __restrict__ exakt detsamma som deras C-motsvarighet. Tillägg inkluderar att tillåta dem att tillämpas på referenstyper och detta .
  • I Visual C++ finns flera no-alias-kvalificerare:
    1. __declspec(restrict) gäller funktionsdeklarationen och antyder att den returnerade pekaren inte är alias.
    2. __restrict används på samma ställe som restrict , men no-alias-tipset sprids inte som i restrict . Det är även utökat för fackföreningstyper .

Kompilatorvarningar

För att förhindra felaktig kod försöker vissa kompilatorer och andra verktyg upptäcka när överlappande argument har skickats till funktioner med parametrar markerade limit . CERT C-kodningsstandarden anser att missbruk av restriktioner och biblioteksfunktioner som är markerade med den (EXP43-C) är en trolig källa till programvarubuggar, även om det i november 2019 inte är känt att några sårbarheter har orsakats av detta.

externa länkar