En lisant Mots-clés qui ne le sont pas (ou commentaires d'un autre nom) par Herb Sutter Je suis tombé sur ces lignes:
C'est vrai, certains mots clés sont sémantiquement équivalents aux espaces blancs, un commentaire glorifié.
Et
Nous avons vu pourquoi le langage C++ traite les mots clés comme des mots réservés, et nous avons vu deux mots clés - auto et register - qui ne font aucune différence sémantique pour un programme C++. Ne les utilisez pas; ils ne sont tout simplement que des espaces, et il existe des moyens plus rapides de taper des espaces.
Si les mots clés comme auto
(peut-être pas en C++ 11) et register
sont sans valeur, alors pourquoi ont-ils été créés et utilisés?
Si cela ne fait aucune différence d'inclure le register
avant une variable
#include<stdio.h>
int main(){
register int a = 15;
printf("%d\n%d\n",&a,a);
return 0;
}
Pourquoi le programme ci-dessus donne-t-il une erreur?
test_register.c: Dans la fonction ‘main’:
test_register.c: 4: 2: erreur: adresse de la variable de registre "a" demandée
printf ("% d\n% d\n", & a, a);
Le programme suivant fonctionne en C++.
#include<iostream>
int main(){
register int a = 15;
std::cout<<&a<<'\n'<<a;
return 0;
}
En C, la classe de stockage register
a été utilisée comme indice pour le compilateur, pour exprimer cela ne variable doit être préférentiellement stockée dans un registre . Notez que le conseil pour stocker une variable register
dans un registre réel peut ou non être respecté, mais dans les deux cas, les restrictions pertinentes s'appliquent toujours. Voir C11, 6.7.1p6 (c'est moi qui souligne):
Une déclaration d'un identifiant pour un objet avec le spécificateur de classe de stockage
register
suggère que l'accès à l'objet soit aussi rapide que possible. La mesure dans laquelle ces suggestions sont efficaces est définie par la mise en œuvre. [note de bas de page 121][note de bas de page 121] L'implémentation peut traiter n'importe quelle déclaration
register
simplement comme une déclarationauto
. Cependant, que le stockage adressable soit réellement utilisé ou non, l'adresse de toute partie d'un objet déclarée avec le spécificateur de classe de stockageregister
ne peut pas être calculée , soit explicitement (en utilisant l'opérateur unaire & comme indiqué au 6.5.3.2) soit implicitement (en convertissant un nom de tableau en un pointeur comme indiqué au 6.3.2.1). Ainsi, les seuls opérateurs pouvant être appliqués à un tableau déclaré avec le spécificateur de classe de stockageregister
sontsizeof
et_Alignof
.
En C++, il s'agit simplement d'un mot clé réservé inutilisé, mais il est raisonnable de supposer qu'il a été conservé pour une compatibilité syntaxique avec le code C.
En C, la classe de stockage auto
définit une variable de stockage automatique, mais elle n'est généralement pas utilisée car les variables fonction-locales sont auto
par défaut .
De même, il est raisonnable de supposer qu'il a été initialement transféré en C++ pour la compatibilité syntaxique uniquement, bien que plus tard, il ait eu sa propre signification ( inférence de type ).
register
en C avait deux objectifs:
Ceci est similaire à const
, qui
À titre d'exemple, considérons cette fonction simpliste:
int sum(const int *values, size_t length) {
register int acc = 0;
for (size_t i = 0; i < length; ++i) {
acc += values[i];
}
return acc;
}
Le programmeur a écrit register
pour garder l'accumulateur hors de la pile, évitant une écriture mémoire à chaque mise à jour. Si l'implémentation devient quelque chose comme ceci:
// Defined in some other translation unit
void add(int *dest, int src);
int sum(const int *values, size_t length) {
register int acc = 0;
for (size_t i = 0; i < length; ++i) {
add(&acc, values[i]);
}
return acc;
}
La variable acc
ne peut plus être stockée dans un registre lorsque son adresse est prise pour l'appel add()
, car les registres n'ont pas d'adresse. Le compilateur signalera donc &acc
Comme une erreur, vous indiquant que vous avez probablement détruit les performances de votre code en empêchant acc
de vivre dans un registre.
Cela était beaucoup plus important au début lorsque les compilateurs étaient plus stupides et que les variables vivaient en un seul endroit pour une fonction entière. De nos jours, une variable peut passer la majeure partie de sa vie dans un registre, étant déplacée sur la pile seulement temporairement lorsque son adresse est prise. Autrement dit, ce code:
/* Passed by reference for some reason. */
void debug(const int *value);
int sum(const int *values, size_t length) {
int acc = 0;
for (size_t i = 0; i < length; ++i) {
acc += values[i];
}
debug(&acc);
return acc;
}
aurait causé acc
à vivre sur la pile pour la fonction entière dans les anciens compilateurs. Les compilateurs modernes conserveront acc
dans un registre juste avant l'appel de debug()
.
Le code C moderne n'utilise généralement pas le mot clé register
.
La justification C99 fournit un peu plus de contexte pour le mot clé register
:
Justification de la Norme internationale - Langages de programmation - C
§6.7.1 Spécificateurs de classe de stockage
Étant donné que l'adresse d'une variable
register
ne peut pas être prise, les objets de la classe de stockageregister
existent effectivement dans un espace distinct des autres objets. (Les fonctions occupent encore un troisième espace d'adressage.) Cela en fait des candidats pour un placement optimal, raison habituelle pour déclarer des registres; mais cela en fait également des candidats à une optimisation plus agressive.