2010-05-28 22 views
14

Könnte jemand bitte den Unterschied erklären, wie die 2 Codefragmente unten behandelt werden? Sie kompilieren auf jeden Fall zu verschiedenen Assembler-Codes, aber ich versuche zu verstehen, wie sich der Code anders verhalten könnte. Ich verstehe, dass String-Literale in schreibgeschützten Speicher geworfen werden und tatsächlich statisch sind, aber wie unterscheidet sich das von der expliziten statischen unten?Unterschied zwischen statischem const char * und const char *

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

und

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

'statisch const char' hat' static' geschrieben vor 'const char' – Iuliu

Antwort

18

Mit Ihrer statischen Version wird es nur eine Variable geben, die irgendwo gespeichert wird und wenn die Funktion ausgeführt wird, wird die exakt gleiche Variable verwendet. Auch für rekursive Aufrufe.

Die nicht statische Version wird für jeden Funktionsaufruf auf dem Stack gespeichert und danach zerstört.

Jetzt Ihr Beispiel ist ein wenig in Bezug kompliziert, was der Compiler tatsächlich nicht so lassen Sie uns zuerst an einem einfacheren Fall aussehen:

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

Und dann ein Haupt etwas wie folgt aus:

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

gedruckt wird

3 
2 

während bei

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

wird es

3 
3 

Jetzt mit Ihrem Beispiel drucken Sie einen const haben, so kann der Wert nicht so der Compiler könnte geändert werden einige Tricks spielen, während es oft keine Wirkung auf der Code generiert, aber hilft dem Compiler Fehler zu erkennen. Und dann haben Sie einen Zeiger, und beachten Sie, dass die Statik Auswirkungen auf den Zeiger selbst hat, nicht auf den Wert, auf den er zeigt. Also wird die Zeichenfolge "Hallo" aus Ihrem Beispiel höchstwahrscheinlich im .data-Segment Ihrer Binärdatei platziert und nur einmal und so lange wie das Programm lebt, unabhängig von der statischen Sache.

+0

Ihre Codebeispiele hier nicht passen, das Wesen der Frage ist die „const“ und die Tatsache, dass es im schreibgeschützten Datensegment platziert wird, so dass der Zeiger auf dieses Zeichen erscheint standardmäßig statisch zu sein, auch wenn Sie tun nicht "statisch" vor "const char *" setzen. –

+1

Vielleicht kann der Compiler diese optimieren und es als statisches behandeln, da wir mit einem Zeiger hier zu tun haben. Dies ist jedoch nicht in allen Fällen möglich: With void foo() {const Balkenleiste; } Der Bar-Standardkonstruktor muss bei jedem Aufruf von foo() als Balken aufgerufen werden, während mit void foo() {static const Balkenleiste; } Der Konstruktor wird höchstens einmal aufgerufen. Auch das char-Array selbst wird immer in schreibgeschützten Segmenten sein, die Frage betrifft die str-Variable. – johannes

10

Eine lokale statische Variable ist das erste Mal seine Definition angetroffen initialisiert, aber nicht wenn die Funktion beendet zerstört. So behält es seinen Wert zwischen Aufrufen der Funktion.

Im Falle eines const ist das nicht ganz hilfreich - zumindest solange der Konstantenwert so leistungsmäßig vernachlässigbar ist wie die Zuweisung einer Adresse. (Wenn das const Objekt nicht ein konstanter Ausdruck ist, oder der Ausdruck nimmt erhebliche Ressourcen zu schaffen - wie in const Foo bar = foobar();, wo foobar() erhebliche Zeit in Anspruch nehmen kann -, könnte der Unterschied wichtig worden.)

Wo es einen Unterschied macht, ist Wenn Sie das Objekt pro Verweis oder Zeiger zurückgeben möchten: Sie können keinen Verweis oder Zeiger auf ein lokales Objekt zurückgeben, es sei denn, es handelt sich um ein lokales statisches Objekt. (Danke an Matthieu für den Hinweis darauf.) Wenn Sie dies jedoch verwenden möchten, müssen Sie daran denken, dass lokale Statik inhärent Thread-unsicher ist.

+1

Ich denke, Sie sollten den Unterschied in der Lebensdauer unterstreichen, können Sie einen Verweis/Zeiger auf die lokale statische zurückgeben, aber es ist undefined, es mit einem Klassiker zu tun Stapelvariable. –

+0

@Matthieu: Du hast Recht, ich hatte nicht daran gedacht. Danke, ich füge das zu meiner Antwort hinzu. – sbi

+1

Und ich bin froh, dass Sie das "threading" Problem Bit hinzugefügt :) Die Leute vergessen oft, dass lokale statische Variablen sind verwandt mit Globals und leiden von all ihren Leiden. –

2

Obwohl es einen technischen Unterschied gibt, sind Ihre beiden Beispiele in Bezug auf Nutzung und Wirkung identisch.

Genauer gesagt, Ihre Verwendung des Schlüsselwortes static gilt für den Zeiger auf das String-Literal, nicht auf das String-Literal selbst. Der Zeiger in Beispiel 1 wird auf dem Stapel platziert, der Zeiger in Beispiel 2 wird mit den statischen Variablen platziert.

Ich würde überrascht sein, wenn sie nicht beide für die gleiche Sache optimiert werden.

7

Ich habe herausgefunden, dass einige Compiler die beiden unterschiedlich behandeln.

Die Version mit const char * kopiert Daten von einem schreibgeschützten Speicherort in eine Variable auf dem Stapel.

Die Version mit static const char * verweist auf die Daten im schreibgeschützten Speicherort (keine Kopie wird durchgeführt).

Ich entdeckte diesen Unterschied beim Durchlaufen des Assembly-Codes einer Funktion mit dem Debugger. Ich schlage vor, dass Sie entweder den Assemblercode ausdrucken oder auf Assemblerebene mit einem Debugger durchgehen, um die genaue Wahrheit zu finden.