2009-09-16 12 views
44

Ich weiß, es ist ziemlich idiomatisch, oder zumindest guter Stil, in C, um numerische Konstanten als enum s statt #define zu deklarieren.Wie deklarieren Sie String-Konstanten in C?

/* bad style */ 
#define MAXLINE 1024 

/* good/better style */ 
enum { 
    MAX_LINE = 1024 
}; 

Gibt es eine äquivalente Regel für die Definition von Stringkonstanten?

/* is this good style? */ 
#define HELLO "Hello World" 

/* or is this better? */ 
const char *HELLO2 = "Howdy"; 

Was bevorzugen Sie? Wenn möglich, zeigen Sie einige Nachteile beider Methoden.

Antwort

70

Es gibt einen weiteren (mindestens) Weg nach Rom:

static const char HELLO3[] = "Howdy"; 

(static - optional - ist es zu verhindern, dass mit anderen Dateien in Konflikt). Ich würde diese über const char* bevorzugen, weil Sie dann in der Lage sein werden, sizeof(HELLO3) zu verwenden, und Sie müssen daher nicht bis zur Laufzeit verschieben, was Sie zur Kompilierzeit tun können.

Die Definition hat einen Vorteil der Kompilierungszeit Verkettung, obwohl (denken Sie HELLO ", World!") und Sie können auch sizeof(HELLO).

Aber dann können Sie auch const char* bevorzugen und es über mehrere Dateien verwenden, die Sie ein Stück Speicher sparen würde.

Kurz gesagt - es kommt darauf an.

+0

Vielen Dank für Ihre Erklärung. Der Grund, 'enum' anstelle von Makrokonstanten oder' const int' für konstante Ganzzahlwerte zu verwenden, ist die Tatsache, dass dies der einzige typsichere Weg ist, eine konstante Ganzzahl zu deklarieren, die portabel als Arraygrenze verwendet werden kann. Nun ... Die String-Verkettung der Kompilierzeit hat mich beinahe dazu gebracht, '# define's für Strings zu verwenden, aber ich bleibe bei' const char * 'für Typ-Sicherheit, wo ich' static' verwende. Kurz gesagt werde ich 'enum' für Integer-Konstanten und' const'-Variablen für den Rest verwenden. –

+1

Tatt, ich würde vorschlagen, dass Sie sich an nichts halten. * Nicht alle Konstanten sind gleich *. Wenn du nicht verketten willst, brauchst du #define nicht, wenn du die Größe auch nicht brauchst, interessiert dich das überhaupt nicht. Was ich absolut nicht sehe, ist, wie 'const char *' besser ist als 'const char []' * wo static anwendbar ist *. Aber wenn Sie die Größe nicht brauchen, ist es auch nicht schlechter ;-) –

9

Ein Vorteil (wenn auch sehr geringe) von String Konstanten definieren, ist, dass Sie sie verketten:

 
#define HELLO "hello" 
#define WORLD "world" 

puts(HELLO WORLD); 

nicht sicher, das ist wirklich ein Vorteil, aber es ist eine Technik, die nicht mit const char verwendet werden kann, * 's.

3

Der Hauptnachteil der #define-Methode ist, dass die Zeichenfolge jedes Mal dupliziert wird, so dass Sie viele Kopien davon in der ausführbaren Datei haben können, wodurch sie größer wird.

+5

Ich glaube, der Compiler wird sie mindestens so lange optimieren, wie sie in der gleichen Datei verwendet werden. Das ist nicht wirklich "jedes Mal, wenn es benutzt wird", aber ja, die Definition der globalen Konstante spart manchmal Platz. –

+2

das ist wahr, es sei denn, der Compiler oder Linker kollabiert die Kopien in eine. Diese Funktion wird manchmal auch als "String-Pooling" bezeichnet. – Rom

-2

Für die erste. Enums sind standardmäßig Ganzzahlen, das bedeutet, dass Sie diesen Wert nur an etwas übergeben können, das nur ganze Zahlen akzeptiert.

Die zweite, die ich besser mag: const Char * Version statt #define. Der Grund dafür ist, dass Arrays in c Zeiger sind, was bedeutet, dass Sie jedes Mal, wenn Sie #define version verwenden möchten, diese Zeichenfolge instanziieren müssen, nur um sie zu verwenden.

+1

Arrays sind keine Zeiger und es gibt kein Konzept von "String Instantiation", wenn es um String-Konstante geht. Und wenn Arrays Zeiger wären, die nicht bedeuten würden, dass die Zeichenfolge instanziiert werden müsste, gäbe es so etwas ;-) –

+0

er sprach über numerische Konstanten. Arrays sind ussualy als Referenzen übergeben. Zumindest kann ich nicht anders denken. So. Was ist die Standardrückgabe in diesem Fall? { const char * str1 = HELLO; const char * str1 = HELLO; Rückkehr (str1 == str2); } –

+0

Der Rückgabewert ist implementierungsabhängig, aber die meisten Implementierungen werden (vorausgesetzt, Sie haben str2 in der zweiten Zuweisung gemeint) true zurückgeben - versuchen Sie es, beide Zeiger verweisen auf dieselbe Zeichenfolge im konstanten Datensegment. Aber dieser Code hat nichts mit Arrays zu tun, es ist ein einfacher Zeiger. Was das Übergeben von Arrays als Zeiger betrifft, bedeutet dies nicht, dass Arrays * * Zeiger sind. 'int *' und 'int [2]' sind verschiedene Typen. Und nicht nur theoretisch - Sie können nicht vernünftig 'sizeof()' Zeiger, Sie können nicht Array, etc. –

7

Wenn Sie einen "const string" wollen, wie Ihre Frage sagt, würde ich wirklich die Version gehen für Sie in Ihrer Frage angegeben:

/* first version */ 
const char *HELLO2 = "Howdy"; 

Besonders würde ich vermeiden:

/* second version */ 
const char HELLO2[] = "Howdy"; 

Grund: Das Problem mit der zweiten Version ist, dass der Compiler eine Kopie der gesamten Zeichenkette "Howdy" macht, PLUS diese Zeichenkette ist modifizierbar (also nicht wirklich const).

Auf der anderen Seite ist die erste Version eine Const-Zeichenfolge, auf die der Const-Zeiger HELLO2 zugreifen kann, und niemand kann sie ändern.

+5

Ich denke 'const char * const HELLO2' ist besser .. – Shawn

Verwandte Themen