Si le compilateur sait qu'il y a seulement un pointeur vers un bloc de mémoire, il peut produire un code mieux optimisé. Nous allons le voir sur un exemple.
Considérons la fonction en C suivante :
void updatePtrs(size_t *ptrA, size_t *ptrB, size_t *val)
{
*ptrA += *val;
*ptrB += *val;
}
La fonction updatePtrs ci-dessus prend 3 pointeurs ptrA, ptrB, et val vers des entiers non signés (size_t) en paramètres. La fonction incrémente les valeurs pointées par ptrA, ptrBde l'entier pointé par val. Les pointeurs ptrA, ptrB, et val peuvent se référer au même emplacement mémoire. C'est pourquoi le compilateur pourrait générer un code moins optimal :
load R1 ← *val ; Charge la valeur pointée par val
load R2 ← *ptrA ; Charge la valeur pointée par ptrA
add R2 += R1 ; Effectuer une Addition
set R2 → *ptrA ; mettre à jour la valeur pointée par ptrA
; De même pour ptrB, notez que val est chargé à deux reprises, parce que
; ptrA peut être égal à val (c'est-à-dire, pointe vers le même emplacement).
load R1 ← *val
load R2 ← *ptrB
add R2 += R1
set R2 → *ptrB
Toutefois, si le mot-clé restrict est utilisé et que la fonction ci-dessus est déclarée comme :
void updatePtrs(size_t *restrict ptrA, size_t *restrict ptrB, size_t *restrict val);
alors le compilateur suppose que ptrA, ptrB et val pointent vers différents emplacements. Ainsi, la mise à jour d'un pointeur n'affectera pas les autres pointeurs. En particulier, on sait que la valeur pointé par val n'est pas modifiée. Il suffit donc de lire la valeur *val une fois seule pour réaliser les deux additions *ptrA += *val; et *ptrB += *val;. Le compilateur peut générer un meilleur code comme suit :
load R1 ← *val
load R2 ← *ptrA
add R2 += R1
set R2 → *ptrA
; Notez que val n'est pas rechargé,
; parce que le compilateur sait que c'est inchangé
load R2 ← *ptrB
add R2 += R1
set R2 → *ptrB
Notez que le code assembleur est plus court parce que la valeur pointée par val n'est chargée qu'une seule fois.
On peut remarquer que dans notre cas, ces deux signatures génèrent aussi le même code :
void updatePtrs(size_t *ptrA, size_t *ptrB, size_t *restrict val);
void updatePtrs(size_t *restrict ptrA, size_t *ptrB, size_t *val);
En effet, il est suffisant de promettre au compilateur que ptrA n'écrira pas dans val , ou que val ne sera pas modifié par ptrA. Ce n'est pas vrai pour ptrB à cause de l'ordre des opérations dans la fonction.
C'est le programmeur (non le compilateur) qui est responsable de veiller à ce que les pointeurs ne pointent pas les mêmes endroits.