famille de langages C, il diffère des constructions similaires d'autres langages en ce qu'il fait partie intégrante du type et présente donc un comportement complexe lorsqu'il est combiné avec des pointeurs , des références, des types de données composites et la vérification de types . Dans d'autres langages, les données ne sont pas stockées à un emplacement mémoire unique , mais copiées à la compilation pour chaque utilisation. Parmi les langages qui l'utilisent, on peut citer C , C++ , D , JavaScript , Julia et Rust .la déclaration d'un objet , indique que l'objet est une constante : sa valeur ne peut pas être modifiée, contrairement à une variable . Cet usage fondamental – déclarer des constantes – se retrouve dans de nombreux autres langages.Cependant, contrairement à d'autres langages, dans la famille des langages C, le type constfait partie du type , et non de l' objet . Par exemple, en C, déclare un objet de type `int` – le type fait partie du type, comme s'il était interprété comme « (const int) x » – tandis qu'en Ada , déclare une constante (une sorte d'objet) de type `int` : le type fait partie de l' objet , mais pas du type .correction de programme , appelée correction par constante . Elle permet une programmation par contrat , où les fonctions spécifient, dans leur signature de type , si elles modifient leurs arguments et si leur valeur de retour est modifiable. Cette vérification de type est principalement pertinente pour les pointeurs et les références – et non pour les types valeur de base comme les entiers – mais aussi pour les types de données composites ou les types paramétrés tels que les conteneurs . Elle est masquée par le fait que `__init__` constpeut souvent être omis, grâce à la coercition de type ( conversion de type implicite ) et au fait que le C utilise le passage par valeur (le C++ et le D utilisent soit le passage par valeur, soit le passage par référence).
Conséquences
La notion de constance n'implique pas que la variable, telle qu'elle est stockée en mémoire, soit inaltérable. constIl s'agit plutôt d'une construction de compilation indiquant ce que le programmeur doit faire, et non nécessairement ce qu'il peut faire. Notez cependant que, dans le cas de données prédéfinies (comme const char*les chaînes de caractères littérales ), le C constest souvent inaltérable.
Distinction par rapport aux constantes
Alors qu'une constante ne change pas de valeur pendant l'exécution du programme, un objet déclaré constpeut, lui, voir sa valeur modifiée. Un exemple courant est celui des registres en lecture seule dans les systèmes embarqués, comme l'état actuel d'une entrée numérique. Les registres de données des entrées numériques sont souvent déclarés comme `int` constet `int` volatile. Le contenu de ces registres peut changer sans intervention du programme (`int` volatile), mais il serait incorrect que le programme tente d'y écrire (`int` const).
Autres utilisations
De plus, une fonction membre (non statique) peut être déclarée comme `const` const. Dans ce cas, le thispointeur à l'intérieur de cette fonction est de type `const` const T*plutôt que simplement de type `int` T*. Cela signifie que les fonctions non constantes de cet objet ne peuvent pas être appelées depuis l'intérieur de cette fonction, et que les variables membres ne peuvent pas être modifiées. En C++, une variable membre peut être déclarée comme `const` mutable, indiquant que cette restriction ne s'applique pas à elle. Dans certains cas, cela peut être utile, par exemple pour la mise en cache , le comptage de références et la synchronisation des données . Dans ces cas, la signification logique (l'état) de l'objet reste inchangée, mais l'objet n'est pas physiquement constant puisque sa représentation binaire peut changer.
Syntaxe
En C, C++ et D, tous les types de données, y compris ceux définis par l'utilisateur, peuvent être déclarés const`const`. La norme `const` impose que toutes les variables et tous les objets soient déclarés comme tels, sauf s'ils doivent être modifiés. Cette utilisation proactive de const`const` rend les valeurs plus faciles à comprendre, à suivre et à interpréter , améliorant ainsi la lisibilité et la compréhensibilité du code. Elle simplifie également le travail en équipe et la maintenance du code, car elle communique des informations sur l'utilisation prévue d'une valeur. Ceci peut aider le compilateur et le développeur lors de l'interprétation du code. Cela peut également permettre à un compilateur optimisant de générer un code plus efficace
Types de données simples
Pour les types de données simples non pointeurs, l'application du constqualificateur est directe. Il peut être placé indifféremment avant ou après certains types pour des raisons historiques (par exemple, `is` const char foo = 'a';est équivalent à ` char const foo = 'a';is`). Sur certaines implémentations, son utilisation constdeux fois (par exemple, ` const char constis` ou ` char const constis`) génère un avertissement, mais pas d'erreur.
Conseils et références
Pour les types pointeur et référence, la signification de `void` constest plus complexe : `void` peut désigner soit le pointeur lui-même, soit la valeur pointée, soit les deux const. De plus, la syntaxe peut prêter à confusion. Un pointeur peut être déclaré comme un constpointeur vers une valeur accessible en écriture, ou un pointeur accessible en écriture vers une constvaleur, ou encore constun pointeur vers constune valeur.pointée ). Les variables de référence en C++ constituent une syntaxe alternative pour constles pointeurs. Un pointeur vers un constobjet, en revanche, peut être réaffecté pour pointer vers une autre adresse mémoire (qui doit être un objet du même type ou d'un type convertible), mais il ne peut pas être utilisé pour modifier la mémoire pointée. Un constpointeur vers un constobjet peut également être déclaré et ne peut ni être utilisé pour modifier la pointée ni être réaffecté pour pointer vers un autre objet. Le code suivant illustre ces subtilités :
int *p, la forme déréférencée *pest un `int` int, tandis que la forme de référence pest un pointeur vers un `int` int. Ainsi, ` constd` modifie le nom à sa droite. La convention C++ consiste plutôt à associer le ` *d` au type, comme dans `d` int* p, et à lire le `d` constcomme modifiant le type à sa gauche. ` const int * cpd` peut donc être lu comme « *cpest un const int`int` » (la valeur est constante), ou comme « cpest un const int *`int` » (le pointeur est un pointeur vers un entier constant). Ainsi :const int*peut être lu comme un pointeur accessible en écriture qui référence un entier non accessible en écriture, et ` int* constint` comme un pointeur non accessible en écriture qui référence un entier accessible en écriture.Une règle plus générale pour faciliter la compréhension des déclarations et définitions complexes fonctionne comme suit :
- trouver l'identifiant de la déclaration en question
- lire aussi loin que possible vers la droite (c'est-à-dire jusqu'à la fin de la déclaration ou jusqu'à la prochaine parenthèse fermante, selon ce qui arrive en premier).
- Revenez à l'endroit où la lecture a commencé et lisez à rebours vers la gauche (c'est-à-dire jusqu'au début de la déclaration ou jusqu'à la parenthèse ouvrante correspondant à la parenthèse fermante trouvée à l'étape précédente).
- Une fois arrivé au début de la déclaration, terminez. Sinon, reprenez à l'étape 2, après la parenthèse fermante précédemment appariée.
Voici un exemple :