const int *var;
const
est un contrat . En recevant un const int *
vous "dites" à l'appelant que vous (la fonction appelée) ne modifierez pas les objets vers lesquels le pointeur pointe.
Votre deuxième exemple explicite rompt ce contrat en supprimant le qualificatif const et en modifiant ensuite l'objet pointé par le pointeur reçu. Ne faites jamais cela.
Ce "contrat" est appliqué par le compilateur. *dummy = 1
ne compilera pas. Le cast est un moyen de contourner cela, en disant au compilateur que vous savez vraiment ce que vous faites et de vous laisser faire. Malheureusement, le "je sais vraiment ce que je fais" n'est généralement pas le cas.
const
peut également être utilisé par le compilateur pour effectuer une optimisation qu'il ne pourrait pas faire autrement.
Note sur le comportement indéfini :
Veuillez noter que si le cast lui-même est techniquement légal, la modification d'une valeur déclarée en tant que const
est un comportement indéfini. Donc techniquement, la fonction originale est ok, tant que le pointeur qui lui est passé pointe vers des données déclarées mutables. Sinon, c'est un comportement indéfini.
Plus d'informations à ce sujet à la fin de l'article
Pour ce qui est de la motivation et de l'utilisation, prenons les arguments suivants strcpy
et memcpy
fonctions :
char* strcpy( char* dest, const char* src );
void* memcpy( void* dest, const void* src, std::size_t count );
strcpy
opère sur des chaînes de caractères, memcpy
opère sur des données génériques. Bien que j'utilise strcpy comme exemple, la discussion suivante est exactement la même pour les deux, mais avec char *
et const char *
pour strcpy
et void *
et const void *
pour memcpy
:
dest
est char *
car dans le tampon dest
la fonction mettra la copie. La fonction va modifier le contenu de ce tampon, donc il n'est pas const.
src
est const char *
parce que la fonction ne lit que le contenu du tampon src
. Il ne le modifie pas.
C'est seulement en regardant la déclaration de la fonction qu'un appelant peut affirmer tout ce qui précède. Par contrat strcpy
ne modifiera pas le contenu du second tampon passé en argument.
const
et void
sont orthogonales. C'est toute la discussion ci-dessus sur const
s'applique à tout type ( int
, char
, void
, ...)
void *
est utilisé en C pour les données "génériques".
Encore plus sur le comportement indéfini :
Cas 1 :
int a = 24;
const int *cp_a = &a; // mutabale to const is perfectly legal. This is in effect
// a constant view (reference) into a mutable object
*(int *)cp_a = 10; // Legal, because the object referenced (a)
// is declared as mutable
Cas 2 :
const int cb = 42;
const int *cp_cb = &cb;
*(int *)cp_cb = 10; // Undefined Behavior.
// the write into a const object (cb here) is illegal.
J'ai commencé par ces exemples car ils sont plus faciles à comprendre. De là, il n'y a qu'un pas vers les arguments de fonction :
void foo(const int *cp) {
*(int *)cp = 10; // Legal in case 1. Undefined Behavior in case 2
}
Cas 1 :
int a = 0;
foo(&a); // the write inside foo is legal
Cas 2 :
int const b = 0;
foo(&b); // the write inside foo causes Undefined Behavior
J'insiste à nouveau : à moins que vous ne sachiez vraiment ce que vous faites, que toutes les personnes travaillant actuellement et à l'avenir sur le code soient des experts et le comprennent, et que vous ayez une bonne motivation, à moins que toutes les conditions ci-dessus soient réunies, ne jamais rejeter la constance !!
7 votes
const T*
signifie que les données a souligné par le pointeur est const. La seconde est très fragile, puisqu'elle rejette le const.1 votes
@ColonelThirtyTwo Mais d'après ce que j'ai lu sur d'autres posts stackoverflow, est-ce que const void* n'est pas souvent utilisé pour empêcher la modification des données ? Mais il me semble qu'en faisant un casting, elle peut être modifiée très facilement.
1 votes
@MoneyBall oui, mais le casting est comme ça. C'est pour cela que le casting est dangereux - je peux prendre votre "const int * " et le convertir en "int64_t * " et SIGSVF ou corrompre d'autres données. Le problème se situe au niveau de la moulage pas les déclarations de const.
0 votes
@M Right, I thought const pourrait empêcher la modification des données. Il s'avère que le C vous permet de le couler et de le modifier sans que cela n'entraîne d'erreur.
0 votes
Excusez ma formulation, mais.... comment stupide serait-il si
const
fonctionnerait dans le cas où l'on fait un cast vers un type non constant ? Imaginez que vous avez un prototype donné pour un callback ou quelque chose qui, pour des raisons internes, a l'argument const. Mais dans le cas où vous savez que VOTRE implémentation ne fournira jamais un argument const OU que vous êtes capable d'attraper le cas où il le sera, POURQUOI le compilateur devrait-il, si vous dites explicitement par un cast qu'il ne doit pas être traité comme constant, le traiter comme constant ?0 votes
@ColonelThirtyTwo : Le second est encore plus fragile puisqu'il passe d'un pointeur int à un pointeur char et change donc alors que le premier exemple accède à au moins 2 octets, le second exemple ne fait que cela.
dummy
Cela pourrait conduire à beaucoup plus de problèmes que la suppression d'un simple qualificateur const, qui n'est de toute façon pas nécessaire dans ce cas.0 votes
@MoneyBall C vous permet de faire beaucoup d'autres choses dangereuses, comme lire/écrire à n'importe quelle adresse mémoire que vous voulez (il suffit d'assigner un pointeur à un entier aléatoire et de le déréférencer), lire/écrire au-delà de la fin d'un tableau et plusieurs autres. Si vous voulez que le compilateur empêche toutes ces choses, vous devriez choisir un autre langage. En retour, vous renoncez à une grande partie du contrôle de bas niveau que le C vous donne, ce qui est une bonne chose. puede qui rendent les programmes écrits dedans si rapides.