J'essaie de comprendre comment le retour d'un pointeur fonctionne dans les scénarios suivants:
5 This string was created in the function.
6 Réponses :
Oui, les pointeurs des littéraux à cordes sont sans danger pour être transmis, tant que vous ne les lisez que d'eux. C'est parce qu'ils sont fondamentalement alloués statiquement par le compilateur, comme celui-ci: si vous voulez faire sauter les choses, essayez d'allouer un tableau réel dans la fonction au lieu d'obtenir un pointeur sur le String littéral. P> char* StringFromFunction()
{
char myString[6] = {'a', ' ', 'l', 'i', 't', '\0'};
return &myString[0];
}
littéraux de chaîne comme "Cette chaîne a été créée dans la fonction." code> est placé en mémoire en lecture seule. Vous n'êtes autorisé que d'attribuer à un
char * code> pour la compatibilité en arrière, il est plus approprié d'utiliser
const char * code> qui reflète avec précision leur nature. P>
Les littéraux de chaîne ne sont pas réellement stockés sur la pile pour la fonction comme des variables automatiques, mais sont stockées sur un emplacement spécial (comme des variables globales). P>
Notez que l'écriture à eux n'est pas portable, il est donc préférable de les utiliser comme const char * code> et non
char * code>. p>.
Est-ce que cet "emplacement spécial" est partie du tas, ou est-il séparé de la pile / du tas?
@ The111 séparé. C'est une section spéciale de l'exécutable, comme la section de code. Dans les fichiers ELF (utilisés sous Linux et d'autres endroits), il s'appelle .rodata code>. Voir la réponse de Sarnold pour plus d'informations.
@ The111 Ils sont généralement stockés dans la section en lecture seule de l'exécutable.
Lorsque je compile votre programme, je reçois un avertissement supplémentaire de Pour éviter l'avertissement, ajouter La boîte à outils GNU stockera le g ++ code>, mon compilateur:
const Code> devant la déclaration de la variable, le type de retour de la fonction et la variable dans la fonction
principale () code>. p>
Cette chaîne a été créée dans la fonction. CODE> String dans la section de données
.RODATA code> Lecture seule, qui est valide pour la durée de vie du programme: P>
$ readelf -p .rodata strings
String dump of section '.rodata':
[ 8] This string was created in the function.
Le moyen le plus simple de voir la différence consiste à générer le disséasemblage d'un simple bonjour-world-ish exemple: ceci est le diassemblage avec GCC dans FreeBSD avec optimisation éteinte P> .file "hellow.c"
.section .rodata
.LC0:
.string "test"
.text
.p2align 4,,15
.globl test
.type test, @function
test:
pushl %ebp
movl %esp, %ebp
movl $.LC0, %eax
popl %ebp
ret
.size test, .-test
.p2align 4,,15
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
call test
movl $0, %eax
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.2.1 20070719 [FreeBSD]"
Cela pourrait être intéressant aussi, mais un peu plus avancé: cs.umd.edu/class/sum2003/cmsc311/notes/mips/dataseg.html
Merci pour cela. Vous venez de m'aider à comprendre beaucoup de réponses. Par exemple, je sais maintenant ce que Rodata fait référence, et je peux maintenant voir comment il existe une zone dans l'exécutable où les littéraux de chaîne sont réellement stockés et la fonction n'a pas réellement créé le littéral à chaîne. Cela me conduit à une autre question. Cela signifie-t-il que je peux accéder au littéral à chaîne sans jamais appeler la fonction?
Oui, vous pouvez dans le même sens que vous pouvez accéder à toutes les variables globales sans les référencer jamais (elles entreraient dans le segment .Data) - sans optimisation. Je ne sais pas que ce compilateur ne les optimise pas si activé - comme cela n'incluait pas la fonction de test si elle n'est pas appelée jamais. Il serait difficile d'y accéder si vous n'avez pas de pointeur. Vous auriez besoin d'astuces sales ou d'assemblage inliné.
La principale chose à comprendre est la la vie em> de l'objet que vous retournez un pointeur (en réalité, l'objet vie est une chose essentielle à comprendre à peu près n'importe quelle instance d'objet). La norme C utilise la terminologie de «durée de stockage» pour la durée de vie de l'objet, car dans C un objet est littéralement une région de stockage de données qui représente des valeurs. P>
Un littéral à chaîne a une "durée de stockage statique", ce qui signifie (C99 6.2.4 / 3): p>
sa durée de vie est l'ensemble de l'exécution du programme et sa valeur stockée n'est initialisée qu'une seule fois, avant le démarrage du programme. P>
blockQuote>
Il n'y a donc aucun problème à renvoyer un pointeur sur un littéral à chaîne d'une fonction (aussi loin que la durée de vie de l'objet, le pointeur se réfère à Go). L'objet littéral à chaîne sera toujours un objet valide. Une chose veille à ce que le pointeur retourné permettra à quelqu'un d'essayer de modifier la gamme de données contenant le littéral à chaîne, qui n'est pas autorisé (ce qui est un comportement indéfini). P>
Le local sa durée de vie s'étend de l'entrée dans le bloc avec lequel elle est associée jusqu'à ce que l'exécution de ce bloc se termine de quelque manière que ce soit p>
blockQuote>
(Notez que la durée de vie d'une matrice de longueur variable automatique est légèrement différente). P>
Donc, le pointeur sur Je pense que la durée de vie de l'objet est l'une des choses fondamentales que chaque programmeur doit comprendre, et il est particulièrement important dans C et C ++, car le programmeur est largement responsable de la manipulation correctement, surtout lorsqu'il s'agit d'un pointeur. P>
int renvoyéValue code> variable de l'autre exemple a la "durée de stockage automatique" qui signifie (C99 6.2.4 / 4): P>
retourvalue code> devient invalide le moment où la fonction renvoie. P>
+1 pour décrire correctement pourquoi i> le comportement est la façon dont il est au lieu de simplement disséquer ce que i> du comportement de la mise en œuvre arbitraire est.
Essayez également: Char * stringfromfunction () {Char [] preturn = "Cette chaîne a été créée dans la fonction."; Return de retour; }