S'il est vrai que le comportement est bien défini - il n'est pas vrai que les compilateurs peuvent "optimiser pour const" dans le sens que vous voulez dire.
Autrement dit, un compilateur n'est pas autorisé à supposer que, simplement parce qu'un paramètre est un const T* ptr
, la mémoire pointée par ptr
ne sera pas modifiée via un autre pointeur. Les pointeurs n'ont même pas besoin d'être égaux. C'est const
une obligation, pas une garantie - une obligation de votre part (= la fonction) de ne pas apporter de modifications via ce pointeur.
Afin d'avoir réellement cette garantie, vous devez marquer le pointeur avec le restrict
mot - clé. Ainsi, si vous compilez ces deux fonctions:
int foo(const int* x, int* y) {
int result = *x;
(*y)++;
return result + *x;
}
int bar(const int* x, int* restrict y) {
int result = *x;
(*y)++;
return result + *x;
}
la foo()
fonction doit lire deux fois x
, alors qu'elle bar()
n'a besoin de la lire qu'une seule fois:
foo:
mov eax, DWORD PTR [rdi]
add DWORD PTR [rsi], 1
add eax, DWORD PTR [rdi] # second read
ret
bar:
mov eax, DWORD PTR [rdi]
add DWORD PTR [rsi], 1
add eax, eax # no second read
ret
Regardez ça en direct GodBolt.
restrict
n'est qu'un mot-clé en C (depuis C99); malheureusement, il n'a pas encore été introduit en C ++ (pour la mauvaise raison qu'il est plus compliqué de l'introduire en C ++). Cependant, de nombreux compilateurs le supportent un peu comme __restrict
.
Conclusion: le compilateur doit prendre en charge votre cas d'utilisation "ésotérique" lors de la compilation f()
et n'aura aucun problème avec celui-ci.
Voir cet article concernant les cas d'utilisation de restrict
.
const
n'est pas «une obligation de votre part (= la fonction) de ne pas apporter de modifications via ce pointeur». La norme C permet à la fonction de supprimerconst
via un cast puis de modifier l'objet à travers le résultat. Essentiellement, ceconst
n'est qu'un conseil et une commodité pour le programmeur pour éviter de modifier un objet par inadvertance.memcpy
etstrcpy
sont déclarés avec desrestrict
arguments, alors que cememmove
n'est pas le cas - seul ce dernier permet le chevauchement entre les blocs de mémoire.C'est bien défini (en C ++, plus sûr en C), avec et sans le
const
qualificatif.La première chose à rechercher est la règle stricte d'alias 1 . Si
src
etdst
pointe vers le même objet:char*
etchar const*
ne sont pas compatibles.char*
etchar const*
sont similaires.En ce qui concerne le
const
qualificatif, vous pourriez faire valoir que, depuis quedst == src
votre fonction modifie effectivement ce quisrc
pointe vers,src
ne doit pas être qualifiée deconst
. Ce n'est pas comme ça que çaconst
marche. Deux cas doivent être considérés:const
, comme danschar const data[42];
, le modifier (directement ou indirectement) conduit à un comportement indéfini.const
objet est défini, comme danschar const* pdata = data;
, on peut modifier l'objet sous-jacent à condition qu'il n'ait pas été défini commeconst
2 (voir 1.). Donc, ce qui suit est bien défini:1) Quelle est la règle stricte d'alias?
2) Est-ce
const_cast
sûr?la source
char*
etchar const*
ne sont pas compatibles._Generic((char *) 0, const char *: 1, default: 0))
évalue à zéro.const
objet est défini» est incorrecte. Vous voulez dire que lorsqu'une référence ou un pointeur vers un typeconst
qualifié est défini, cela ne signifie pas que l'objet sur lequel il doit pointer ne peut pas être modifié (par divers moyens). (Si le pointeur pointe vers un objet, cela signifie que l'objet est en effet par définition, donc le comportement d'essayer de le modifier n'est pas défini.)const
const
language-lawyer
. L'exactitude est une valeur que je chéris, mais je suis également consciente qu'elle s'accompagne de plus de complexité. Ici, j'ai décidé d'opter pour la simplicité et les phrases faciles à comprendre, car je crois que c'est ce que OP souhaitait. Si vous pensez le contraire, veuillez répondre, je serai parmi les premiers à le voter. Quoi qu'il en soit, merci pour ton commentaire.Ceci est bien défini dans C. Les règles d'alias strictes ne s'appliquent pas avec le
char
type, ni avec deux pointeurs du même type.Je ne sais pas trop ce que vous entendez par "optimiser pour
const
". Mon compilateur (GCC 8.3.0 x86-64) génère exactement le même code pour les deux cas. Si vous ajoutez lerestrict
spécificateur aux pointeurs, le code généré est légèrement meilleur, mais cela ne fonctionnera pas pour votre cas, les pointeurs étant les mêmes.(C11 §6.5 7)
Dans ce cas (sans
restrict
), vous obtiendrez toujours121
le résultat.la source