restringir - restrict
Na linguagem de programação C , restrict
é uma palavra - chave que pode ser usada em declarações de ponteiro . Ao adicionar esse qualificador de tipo , um programador sugere ao compilador que, durante a vida útil do ponteiro, apenas o próprio ponteiro ou um valor diretamente derivado dele (como pointer + 1
) será usado para acessar o objeto para o qual ele aponta.
restrict
limita os efeitos do aliasing do ponteiro , auxiliando nas otimizações . Se a declaração de intenção não for seguida e o objeto for acessado por um ponteiro independente, isso resultará em um comportamento indefinido . O uso desse qualificador de tipo permite que o código C obtenha o mesmo desempenho que o mesmo programa escrito em Fortran . Foi introduzido no padrão C99 .
C ++ não tem suporte padrão para restrict
, mas muitos compiladores têm equivalentes que geralmente funcionam em C ++ e C, como GCC 's e Clang 's __restrict__
, e Visual C ++ 's __declspec(restrict)
. Além disso, __restrict
é compatível com esses três compiladores. A interpretação exata dessas palavras-chave alternativas varia de acordo com o compilador:
- Em compiladores de estilo Unix, como GCC e Clang,
__restrict
e__restrict__
significam exatamente o mesmo que sua contraparte C. As extensões incluem permitir que sejam aplicados a tipos de referência ethis
. - No Visual C ++, vários qualificadores sem alias são fornecidos:
-
__declspec(restrict)
aplica-se à declaração da função e sugere que o ponteiro retornado não tem um alias. -
__restrict
é usado no mesmo lugar querestrict
, mas a dica sem alias não se propaga como emrestrict
. Ele também é estendido para tipos de união .
-
Otimização
Se o compilador souber que existe apenas um ponteiro para um bloco de memória, ele pode produzir um código melhor otimizado. Por exemplo:
void updatePtrs(size_t *ptrA, size_t *ptrB, size_t *val)
{
*ptrA += *val;
*ptrB += *val;
}
No código acima, os ponteiros ptrA
, ptrB
e val
podem referir-se ao mesmo local de memória , portanto, o compilador pode gerar código menos ideal:
; Hypothetical RISC Machine.
ldr r12, [val] ; Load memory at val to r12.
ldr r3, [ptrA] ; Load memory at ptrA to r3.
add r3, r3, r12 ; Perform addition: r3 = r3 + r12.
str r3, [ptrA] ; Store r3 to memory location ptrA, updating the value.
ldr r3, [ptrB] ; 'load' may have to wait until preceding 'store' completes.
ldr r12, [val] ; Have to load a second time to ensure consistency.
add r3, r3, r12
str r3, [ptrB]
No entanto, se a restrict
palavra-chave for usada e a função acima for declarada como
void updatePtrs(size_t *restrict ptrA, size_t *restrict ptrB, size_t *restrict val);
em seguida, o compilador é permitido supor que ptrA
, ptrB
e val
apontam para diferentes locais e atualizar o local de memória referenciado por um ponteiro não afetará as posições de memória referenciados por outros ponteiros. O programador, não o compilador, é responsável por garantir que os ponteiros não apontem para locais idênticos. O compilador pode, por exemplo, reorganizar o código, primeiro carregando todos os locais da memória e, em seguida, executando as operações antes de comprometer os resultados de volta na memória.
ldr r12, [val] ; Note that val is now only loaded once.
ldr r3, [ptrA] ; Also, all 'load's in the beginning ...
ldr r4, [ptrB]
add r3, r3, r12
add r4, r4, r12
str r3, [ptrA] ; ... all 'store's in the end.
str r4, [ptrB]
O código de montagem acima é mais curto porque val
é carregado apenas uma vez. Além disso, como o compilador pode reorganizar o código com mais liberdade, ele pode gerar um código que executa mais rapidamente. Na segunda versão do exemplo acima, todas as store
operações ocorrem após as load
operações, garantindo que o processador não precise bloquear no meio do código para esperar até que as store
operações sejam concluídas.
Observe que o código real gerado pode ter comportamentos diferentes. O benefício com o mini-exemplo acima tende a ser pequeno e, em casos da vida real, grandes loops que realizam um acesso pesado à memória tendem a ser o que realmente ajuda com a restrição.
Conforme mencionado acima, como o código incorreto se comporta é indefinido , o compilador apenas garante que o código gerado funcione corretamente se o código seguir a declaração de intenção.
Avisos do compilador
Para ajudar a evitar código incorreto, alguns compiladores e outras ferramentas tentam detectar quando argumentos sobrepostos foram passados para funções com parâmetros marcados restrict
. O CERT C Coding Standard considera o uso indevido restrict
e as funções de biblioteca marcadas com ele (EXP43-C) uma provável fonte de bugs de software, embora em novembro de 2019 nenhuma vulnerabilidade tenha sido causada por isso.
Referências
-
"ISO / IEC 9899: Rascunho do Comitê TC2" (PDF) . ISO . 6 de maio de 2005: 108-112 . Página visitada em 22/12/2008 . Citar diário requer
|journal=
( ajuda )
links externos
- Desmistificando a palavra-chave restrita : explicação e exemplos de uso
- Walls, Douglas. "Como usar o qualificador restrito em C" . Oracle ™ . Página visitada em 2012-11-21 .
- Ponteiros restritos em C : a lógica original por trás da definição