2014-10-09 12 views
6

Vorrei chiedere se è possibile fare affidamento sull'indirizzo letterale stringa tra le unità di traduzione? Per esempio:Stringa Indirizzo letterale su unità di traduzione

Un dato file foo.c ha un riferimento a una stringa letterale "I'm a literal!", è corretto e portatile per contare che in altre file specificato, bar.c in esempio, che il stessa stringa letterale"I'm a literal!" avranno la stessa memoria indirizzo? Considerando che ogni file verrà tradotto in un singolo file .o.

Per una migliore illustrazione, segue un codice di esempio:

# File foo.c 
/* ... */ 
const char * x = "I'm a literal!" 

# File bar.c 
/* ... */ 
const char * y = "I'm a literal!" 

# File test.c 
/* ... */ 
extern const char * x; 
extern const char * y; 
assert (x == y); //Is this assertion going to fail? 

E un gcc righe di comando esempio:

gcc -c -o foo.o -Wall foo.c 
gcc -c -o bar.o -Wall bar.c 
gcc -c -o test.o -Wall test.c 
gcc -o test foo.o bar.o test.o 

Che dire nella stessa unità di traduzione? Questo sarebbe affidabile se i valori letterali delle stringhe sono nello stesso unità di traduzione?

+7

No, non puoi fidarti di questo. –

+0

@NeilKirk Grazie Neil, ho modificato e aggiunto una domanda secondaria. Qualsiasi logica alla base sarebbe di grande illuminazione. –

+2

@fanl - La suite di compilatori Visual C++ ha un'opzione di "pooling di stringhe" in cui lo stesso letterale avrà lo stesso valore di puntatore. La parola chiave nell'ultima frase è * opzione *. Ciò implica che non è possibile fare affidamento sul fatto che i valori del puntatore sono uguali. – PaulMcKenzie

risposta

10

Non è possibile fare affidamento su valori di stringa identici con la stessa posizione di memoria, è una decisione di implementazione. Il C99 draft standard ci dice che è specificato se la stessa stringa letterale sono distinte, dalla sezione 6.4.5Le stringhe:

È specificato se queste matrici sono distinti fornito loro elementi hanno i valori appropriati. Se il programma tenta di modificare una tale matrice, il comportamento non è definito.

Per C++ questo trattato nel progetto di sezione standard 2.14.5Le stringhe che dice:

Se tutte le stringhe letterali sono distinte (cioè, vengono memorizzate in oggetti sovrapposti) è Attuazione definito. L'effetto di nel tentativo di modificare un valore letterale stringa non è definito.

Il compilatore è permesso piscina stringhe letterali, ma si dovrebbe capire come funziona da compilatore a compilatore e quindi questo non sarebbe portatile e potrebbe potenzialmente cambiare. Visual Studio include un option for string literal pooling

In alcuni casi, identici stringhe letterali possono essere raggruppati per risparmiare spazio nel file eseguibile. Nel pooling stringa-letterale, il compilatore causa tutti i riferimenti a una stringa letterale specifica per puntare alla stessa posizione nella memoria, invece di avere ogni punto di riferimento su un'istanza separata della stringa letterale . Per abilitare il pooling di stringhe, utilizzare l'opzione del compilatore/GF.

Nota che si qualifica con In alcuni casi.

gcc fa sostegno messa in comune e attraverso unità di compilazione e si può accenderlo tramite -fmerge-constants:

tenta di unire le costanti identici (costanti stringa e le costanti in virgola mobile) attraverso unità di compilazione.

Questa opzione è l'impostazione predefinita per la compilazione ottimizzata se l'assemblatore e il linker lo supportano. Utilizzare le costanti -fno-merge per inibire questo comportamento .

nota, l'uso di tentativo e se ... sostenerlo.

quanto di una logica almeno per C per non richiedere stringhe essere aggregate possiamo vedere da questo archived comp.std.c discussion on string literals che la logica era a causa della grande varietà di attuazione al momento:

GCC potrebbe essere servito come esempio ma non come motivazione. In parte il desiderio di di avere valori letterali di stringa nei dati ROMmable era di supportare, er, ROMming. Ricordo vagamente di aver utilizzato un paio di implementazioni C (prima che venisse presa la decisione X3J11) dove i valori letterali delle stringhe erano o raggruppati automaticamente o memorizzati in una sezione di programma dati costante. Data la varietà esistente di pratica e la disponibilità di una facile soluzione quando si desideravano le proprietà UNIX originali, era preferibile non utilizzare per garantire l'univocità e la scrittura dei valori letterali delle stringhe .

+1

Vuoi dire che entrambi, aspettandosi che l'indirizzo sia lo stesso all'interno e all'interno delle unità di traduzione, sono inaffidabili? –

+2

@fanl Questo è quello che ha detto. Nel K & R C originale, ogni stringa letterale era garantita come univoca, con un indirizzo diverso (e ti era permesso di modificare un letterale stringa); lo standard C originale lo ha modificato, e _permitted_ stringhe letterali identiche per avere lo stesso indirizzo. –

+0

@fanl non è affidabile in tutti i casi, anche se i compilatori supportano il pooling, sia 'gcc' che' Visual Studio' indicano nei loro documenti che si applica solo in * alcuni casi *. –

3

No, non è possibile aspettarsi lo stesso indirizzo. Se succede, succede. Ma non c'è nulla che lo imponga.

§ 2.14.5/p12

Se tutte le stringhe letterali sono distinte (cioè, vengono memorizzate in oggetti sovrapposti) è definita attuazione. L'effetto di nel tentativo di modificare un valore letterale stringa non è definito.

Il compilatore può fare tutto ciò che desidera. Possono essere memorizzati in indirizzi diversi se si trovano in diverse unità di traduzione o anche se si trovano nella stessa unità di traduzione, indipendentemente dal fatto che siano memoria di sola lettura.

In MSVC, per esempio, gli indirizzi sono totalmente diverse nei due casi, ma di nuovo: nulla impedisce al compilatore di fondere i valori dei puntatori (neppure dove, per quanto riguarda il vincolo sezione di sola lettura è obbligato).