Différence entre static const char * et const char *

Quelqu’un pourrait-il s’il vous plaît expliquer la différence dans la façon dont les 2 extraits de code sont traités ci-dessous? Ils comstacknt définitivement dans un code d’assemblage différent, mais j’essaie de comprendre comment le code pourrait agir différemment. Je comprends que les littéraux de chaîne sont jetés dans la mémoire en lecture seule et sont effectivement statiques, mais en quoi est-ce différent du statique explicite ci-dessous?

struct Obj1 { void Foo() { const char* str( "hello" ); } }; 

et

 struct Obj2 { void Foo() { static const char* str( "hello" ); } }; 

Avec votre version statique, une seule variable sera stockée quelque part et, chaque fois que la fonction sera exécutée, la même variable sera utilisée. Même pour les appels récursifs.

La version non statique sera stockée sur la stack pour chaque appel de fonction et détruite après chacun.

Maintenant, votre exemple est un peu compliqué en ce qui concerne ce que le compilateur fait en réalité, examinons d’abord un cas plus simple:

 void foo() { static long i = 4; --i; printf("%l\n", i); } 

Et puis quelque chose comme ça:

 int main() { foo(); foo(); return 0; } 

imprimera

 3 2 

alors qu’avec

 void foo() { long i = 4; --i; printf("%l\n", i); } 

ça va imprimer

 3 3 

Maintenant, avec votre exemple, vous avez un const. Ainsi, la valeur ne peut pas être modifiée. Le compilateur peut donc jouer quelques astuces, alors que cela n’a souvent aucun effet sur le code généré, mais aide le compilateur à détecter les erreurs. Et puis vous avez un pointeur, et n’oubliez pas que la statique a des effets sur le pointeur lui-même, pas sur la valeur qu’il pointe. Ainsi, la chaîne “hello” de votre exemple sera probablement placée dans le segment .data de votre fichier binary, et une seule fois, et vivra tant que le programme restra en vie, indépendamment de l’élément statique.

Une variable statique locale est initialisée la première fois que sa définition est rencontrée mais n’est pas détruite à la sortie de la fonction. Donc, il garde sa valeur entre les invocations de la fonction.

Dans le cas d’un const ce n’est pas très utile – du moins, tant que la construction de la valeur constante est aussi négligeable en termes de performances que l’atsortingbution d’une adresse. (Si l’object const n’est pas une expression constante, ou si l’expression nécessite des ressources considérables pour créer – comme dans const Foo bar = foobar(); foobar()foobar() peut prendre un temps considérable -, la différence pourrait devenir importante.)

La différence se produit lorsque vous souhaitez renvoyer l’object par référence ou par pointeur: Vous ne pouvez pas renvoyer une référence ou un pointeur sur un object local, à moins qu’il ne s’agisse d’un object statique local. ( Merci à Matthieu de l’avoir signalé. ) Toutefois, lorsque vous souhaitez utiliser cette fonctionnalité, vous devez garder à l’esprit que la statique locale est insortingnsèquement thread-unsafe.

J’ai découvert que certains compilateurs traitent les deux différemment.

La version avec const char * copiera les données d’un emplacement en lecture seule vers une variable de la stack.

La version avec static const char * référence les données dans l’emplacement en lecture seule (aucune copie n’est effectuée).

J’ai découvert cette différence en parcourant le code d’assemblage d’une fonction à l’aide du débogueur. Je vous suggère d’imprimer le code de l’assemblage ou de procéder, au niveau du langage d’assemblage, avec un débogueur pour rechercher la vérité exacte.

Bien qu’il y ait une différence technique, en termes d’utilisation et d’effet, vos deux exemples sont identiques.

De manière plus détaillée, votre utilisation du mot-clé static s’applique au pointeur sur le littéral de chaîne, et non sur le littéral de chaîne lui-même. Le pointeur de l’exemple 1 sera placé sur la stack, le pointeur de l’exemple deux sera placé avec les variables statiques.

Je serais surpris si les deux ne sont pas optimisés pour la même chose cependant.