Où le stockage littéral constant C ++ en mémoire?

Où le stockage littéral constant C ++ en mémoire? stack ou tas?

int *p = &2

est faux. Je veux savoir pourquoi? Merci

————————————————-

Ma question est “Où le stockage littéral constant C ++ en mémoire”, ” int *p = &2

est faux “, pas ma question.

Les détails dépendent de la machine, mais en supposant le type de machine et de système d’exploitation le plus courant … chaque fichier exécutable contient plusieurs “segments” – CODE, BSS, DATA et quelques autres.

CODE contient tous les opcodes exécutables. En fait, on l’appelle souvent TEXT parce que cela avait du sens pour les gens il y a des décennies. Normalement, c’est en lecture seule.

Les services BSS sont des données non initialisées. En fait, ils n’ont pas besoin d’exister dans le fichier exécutable, mais ils sont alloués par le chargeur du système d’exploitation lorsque le programme commence à s’exécuter.

DATA contient les constantes littérales – int8, int16, int32, etc., ainsi que des flottants, des littéraux de chaîne et tout ce qui est étrange que le compilateur et l’éditeur de liens se chargent de produire. C’est ce que vous demandez. Cependant, il ne contient que les constantes définies pour être utilisées comme variables, comme dans

 const long x = 2; 

mais il est peu probable que des constantes littérales soient utilisées dans votre code source mais ne soient pas étroitement associées à une variable. Juste un seul ‘2’ est traité directement par le compilateur. Par exemple en C,

 print("%d", 2); 

obligerait le compilateur à créer un appel de sous-routine à print (), écrivant des codes opération pour pousser un pointeur sur le littéral de chaîne “% d” et la valeur 2, tous deux sous la forme d’entiers 64 bits sur une machine 64 bits (vous n’êtes pas connecté). un de ces retardataires utilisant encore du matériel 32 bits, êtes-vous? 🙂 suivi de l’opcode pour passer à un sous-programme à (identificateur du sous-programme ‘print’).

Le littéral “% d” va dans DATA. Le 2 ne le fait pas; il est intégré à l’opcode qui emstack des entiers dans la stack. Cela pourrait en fait être un “registre de charge RAX immédiat” suivi de la valeur 2, suivi d’un “registre de poussées RAX”, ou peut-être un seul opcode pourrait faire l’affaire. Donc, dans le fichier exécutable final, le 2 se trouvera dans le segment CODE (aka TEXT).

Il n’est généralement pas possible de faire un pointeur sur cette valeur, ni sur aucun code d’opération. Cela n’a aucun sens en termes de langage de haut niveau comme C (et C est “de haut niveau” quand vous parlez d’opcodes et de segments). “& 2” ne peut être qu’une erreur.

Maintenant, il n’est pas tout à fait impossible d’avoir un pointeur sur les opcodes. Chaque fois que vous définissez une fonction en C, ou une méthode object, un constructeur ou un destructeur en C ++, le nom de la fonction peut être considéré comme un pointeur sur le premier code opération du code machine compilé à partir de cette fonction. Par exemple, print () sans les parenthèses est un pointeur sur une fonction. Peut-être que si votre exemple de code faisait partie d’une fonction et que vous devinez le bon décalage, l’arithmétique de pointeur pourrait être utilisée pour pointer sur cette valeur “immédiate” 2 nichée parmi les opcodes, mais cela ne va pas être facile pour un processeur contemporain, et certainement n’est pas pour les débutants.

Permettez-moi de citer les clauses pertinentes de C ++ 03 Standard. 5.3.1 / 2

Le résultat de l’opérateur unaire est un pointeur sur son opérande. L’opérande doit être une valeur.

Un littéral entier est une valeur rvalue (cependant, je n’ai pas trouvé de citation directe dans C ++ 03 Standard, mais C ++ 11 le mentionne comme note secondaire dans 3.10 / 1). Par conséquent, il n’est pas possible de prendre une adresse d’un littéral entier.

Qu’en est-il de l’endroit exact où 2 est stocké, cela dépend de l’utilisation. Cela peut faire partie d’une instruction machine ou être optimisé, par exemple j=i*2 peut devenir j=i+i . Vous ne devriez pas compter dessus.

Vous avez deux questions:

Où sont stockées les constantes littérales? À l’exception des littéraux de chaîne (qui sont des objects réels), à peu près partout où l’implémentation le souhaite. Cela dépendra généralement de ce que vous en ferez, mais dans beaucoup d’architectures, les constantes intégrales (et souvent des constantes spéciales à virgule flottante, telles que 0.0 ) se retrouveront dans le cadre d’une instruction machine. Lorsque ce n’est pas possible, ils seront généralement placés dans le même segment logique que le code.

Quant à savoir pourquoi prendre l’adresse d’une valeur est illégale, la raison principale est que la norme le dit. Historiquement, c’est interdit, car de telles constantes n’existent souvent jamais en tant qu’object séparé en mémoire et n’ont donc pas d’adresse. Aujourd’hui … on pourrait imaginer d’autres solutions: les compilateurs sont assez intelligents pour les mettre en mémoire si vous prenez leur adresse, et pas autrement; et les valeurs de type de classe ont une adresse mémoire. Les règles sont quelque peu arbitraires (et le seraient, indépendamment de ce qu’elles étaient) – heureusement, toute règle permettant de prendre l’adresse d’un littéral rendrait son type int const* , et non int* .