2012-07-09 12 views
19

appena stato ispezionare il seguente in gdb:ottimizzazione C di stringhe letterali

char *a[] = {"one","two","three","four"}; 
char *b[] = {"one","two","three","four"}; 
char *c[] = {"two","three","four","five"}; 
char *d[] = {"one","three","four","six"}; 

e ottengo il seguente:

(gdb) p a 
$17 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"} 
(gdb) p b 
$18 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"} 
(gdb) p c 
$19 = {0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four", 0x80961b7 "five"} 
(gdb) p d 
$20 = {0x80961a4 "one", 0x80961ac "three", 0x80961b2 "four", 0x80961bc "six"} 

Sono davvero sorpreso che i puntatori di stringa sono gli stessi per equivalente parole. Avrei pensato che a ogni stringa sarebbe stata assegnata la propria memoria nello stack indipendentemente dal fatto che fosse uguale a una stringa in un altro array.

È un esempio di ottimizzazione del compilatore o comportamento standard per la dichiarazione di stringhe di questo tipo?

+1

Da dove arriva lo "stack" in questa domanda? Se hai dichiarato 'a',' b', 'c' e' d' come variabili locali, devi dirlo nella tua domanda. – AnT

+0

sì - sono variabili locali di durata automatica dichiarate all'interno di una funzione quindi nello stack – bph

+2

Sì. È un esempio di ottimizzazione del compilatore. – Jack

risposta

24

Si chiama "pooling di stringhe". È facoltativo in Microsoft Compilers, ma non in GCC. Se si disattiva il pooling di stringhe in MSVC, le stringhe "uguali" nei diversi array verrebbero duplicate e avrebbero indirizzi di memoria diversi, e quindi richiederebbero un extra (non necessario) 50 o più byte dei dati statici.

MODIFICA: gcc fa in effetti ha un'opzione, -fwritable-strings che disabilita il pooling di stringhe. L'effetto di questa opzione è duplice: consente di sovrascrivere i valori letterali stringa e di disabilitare il pooling di stringhe. Quindi, nel tuo codice, l'impostazione di questo flag consentirebbe il codice un po 'pericoloso

/* Overwrite the first string in a, so that it reads 'xne'. Does not */ 
/* affect the instances of the string "one" in b or d */ 
*a[0] = 'x'; 
+4

In GCC (almeno 4.7) un interruttore per disabilitare il pooling è -fno-merge-constants. – dbrank0

+3

@ nota dbrank0 che [gcc non supporta più fwritabe-Srings] (https://gcc.gnu.org/gcc-4.0/changes.html), sarebbe ideale per aggiungere entrambe queste note per la tua risposta. –

7

(suppongo che il tuo a, b, c e d sono dichiarate come variabili locali, che è la ragione per le vostre aspettative di stack-correlato.)

letterali stringa in C hanno una durata di archiviazione statica. Non vengono mai assegnati "in pila". Sono sempre allocati nella memoria globale/statica e vivono "per sempre", vale a dire finché il programma viene eseguito.

Gli array a, b, c e d sono stati allocati nello stack. I puntatori memorizzati in questi array puntano alla memoria statica. In queste circostanze, non c'è nulla di insolito nei puntatori per le stesse parole identiche.

Se un compilatore unirà letterali identici in uno dipende dal compilatore. Alcuni compilatori hanno anche un'opzione che controlla questo comportamento. I valori letterali stringa sono sempre di sola lettura (motivo per cui è consigliabile utilizzare il tipo const char * per gli array), quindi non fa molta differenza se sono unificati o meno, fino a quando non si inizia a fare affidamento sui valori dei puntatori effettivi.

P.S. Solo per curiosità: anche se questi letterali stringa sono stati allocati nello stack, perché ti aspetteresti che i letterali identici vengano "istanziati" più di una volta?

+1

grandi cose - questo è aiutato la mia comprensione molto, non avevano pienamente compreso la roba letterale stringa e la sua durata di storage associato - stavo pensando in modo non corretto delle corde come solo essere variabili locali (automatici) nello stack – bph

+2

Niente che io sappia, dice che due (o più) riferimenti alla stessa stringa letterale * deve * risolutezza nella stessa posizione di memoria. Il compilatore potrebbe (e alcuni lo fanno) allocare spazio per ogni stringa letterale, anche se alcuni sono "duplicati". Vedi "pooling di stringhe" menzionato da @Josh. –