Que signifie vraiment const
? La lecture seule semble résumer sa signification pour moi, mais je ne suis pas sûre d'avoir raison.
Si en lecture seule et const
sont différents, quelqu'un pourrait-il me dire pourquoi?
La question qui a motivé cette question était cette réponse où il déclare const
"juste" signifie en lecture seule en C. Je pensais que cela voulait dire allconst
, que ce soit en C ou C++. Que veut-il dire?
Pour répondre aux différences spécifiques entre const
en C et C++, j'ai créé une nouvelle question: En quoi "const" diffère-t-il en C et C++? Selon la suggestion de R. ...
En déclarant une variable en tant que const
, vous indiquez au compilateur que vous n’avez aucune intention de modifier cette variable. Mais cela ne signifie pas que les autres n'en ont pas! C'est juste pour permettre une optimisation et être averti par une erreur de compilation (notez qu'il s'agit principalement d'une erreur de compilation, alors que const == ReadOnly
signifierait des erreurs d'exécution).
const
ne signifie pas en lecture seule, car vous pouvez écrire const volatile
, cela signifierait que il pourrait changer par lui-même à tout moment, mais je n'ai pas l'intention de le modifier.
EDIT: voici un exemple classique: considérez que j’écris le code qui lit l’heure actuelle à partir d’un port mappé en mémoire. Considérez que RTC est associé à la mémoire DWORD 0x1234.
const volatile DWORD* now = (DWORD*)0x1234;
C'est const
parce que c'est un port en lecture seule, et c'est volatile
car chaque fois que je le lirai, cela changera.
Notez également que de nombreuses architectures rendent effectivement les variables globales déclarées comme étant const
en lecture seule, car il est UB de les modifier. Dans ces cas, UB se manifestera par une erreur d'exécution. Dans d'autres cas, ce serait un vrai UB :)
Voici une bonne lecture: http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html
Le compilateur n'autorisera pas la modification de quelque chose déclaré comme const
. C'est comme tu dis.
Il est principalement utilisé dans les prototypes de fonctions pour informer l'utilisateur qu'une fonction ne touchera pas ceci ou cela lorsque des pointeurs seront transmis. Cela fonctionne aussi comme une sorte de sécurité intégrée pour vous-même.
Beaucoup de gens vous disent que const
signifie que vous ne pouvez pas le modifier. C'est manifestement faux. const
peut être trivialement jeté. Notez cet extrait:
void foo(const int *somevalue)
{
int *p = (int*) somevalue;
*p = 256; // OMG I AM EVIL!!!!11
}
Votre compilateur ne vous empêchera pas de le faire. Alors, quel est le but de const
? Je l'appellerais plus d'une suggestion. Cela vous rappelle que vous examinez les prototypes de fonctions du contrat que vos fonctions attendent. Votre compilateur va crier après vous si vous le casser négligemment. (Mais pas si vous le cassez intentionnellement, comme avec la distribution ci-dessus.)
Dans certains cas, la norme rompt intentionnellement const
. Notez les valeurs de retour de strstr
par exemple: par définition, il retournera un certain décalage dans le tampon const
que vous le fournissez ... Mais la valeur renvoyée n'est pas const
. Pourquoi? Eh bien, cela serait rompu de manière significative en utilisant la valeur de retour de strstr
sur un tampon non -const
.
Deux octets pour octet identique (à l'exception des commentaires), exemples de cas minimaux ...
D'abord en C, gcc émettra un avertissement ...
/* Fonction prenant un pointeur sur un tableau de deux entiers en lecture seule. */ void a (const int (* parray) [2]); void b (void) { int array [2] = {1,2}; const int crray [2] = {1,2}; /* C se réserve le droit de conserver cette information dans un emplacement en lecture seule. */ un (& tableau); /* warning: passer l’argument 1 de ‘a’ à partir d’un type de pointeur incompatible */ un (& crray); /* D'ACCORD!*/ }
Maintenant, la même chose en C++ ... g ++ en est assez content.
// Fonction prenant un pointeur sur un tableau // de deux entiers qu’elle ne promet pas de modifier. // (Sauf si nous rejetons sa constance ;-P) Void a (const int (* parray) [2]); Void b (void) { int array [2] = {1,2}; const int crray [2] = {1,2}; un (& tableau); // C++ n'a pas de problème avec ceci . un (& crray); // D'ACCORD! }
const char * hello_1{ "Hello!" };
const char hello_2[]{ "Hello!" };
char * ptr{};
// take away the const-nes
// ptr = (char *)hello_1;
// *ptr = '*'; <-- write access violation
// hello_1 is in a read only memory
// take away the const-nes
ptr = (char *)hello_2;
*ptr = '*'; // <-- OK
// hello_2 is modifiable
Les pointeurs pointent vers la mémoire et char *
pointe vers la mémoire dans le segment de données qui est en lecture seule. La différence entre char *
et char []
est que, bien que les deux soient déclarés de la même manière sur le segment de données, char []
est considéré comme lisible, car il est poussé dans la pile s'il est utilisé.