Warum verwenden die meisten C-Entwickler define statt const? [duplicate]

Lesezeit: 8 Minuten

Benutzeravatar von C. Ross
Kreuz

In vielen Programmen a #define dient dem gleichen Zweck wie eine Konstante. Zum Beispiel.

#define FIELD_WIDTH 10
const int fieldWidth = 10;

Ich sehe häufig, dass die erste Form der anderen vorgezogen wird, wobei ich mich auf den Vorprozessor verlasse, um das zu handhaben, was im Grunde eine Anwendungsentscheidung ist. Gibt es einen Grund für diese Tradition?

  • Beachten Sie, dass Sie für ganzzahlige Konstanten auch eine Aufzählung wie in “enum {FIELD_WIDTH = 10};´´ verwenden können, was nützlich sein kann, wenn Sie eine Konstante zur Kompilierzeit in einem Funktionsumfang benötigen.

    – Jochen Walter

    26. Oktober 2010 um 14:16 Uhr


  • Sie können #define auch im Funktionsumfang verwenden, obwohl Sie daran denken müssen, es am Ende der Funktion #undef zu machen

    – Goldesel

    26. Oktober 2010 um 14:58 Uhr

  • @CashCow: Das ist richtig, aber dann definierst du ein mögliches #define im Dateibereich (das möglicherweise in einer Include-Datei definiert wurde, die du nicht selbst geschrieben hast).

    – Jochen Walter

    26. Oktober 2010 um 15:18 Uhr

  • @Jochen: Wenn es eine Kollision mit einer anderen Makrodefinition gibt, dann hat Ihr #define bereits die vorherige Definition überschrieben und Sie haben eine Compiler-Warnung ignoriert, also können Sie es auch #undef und einen Compiler-Fehler erzeugen, wenn das Makro verwendet wird weiter unten in Ihrem Code, um Sie daran zu erinnern, dass Sie den Makronamen für Ihr Funktionsbereichsmakro ändern sollten.

    – Sicher

    26. Oktober 2010 um 15:49 Uhr

  • @Secure: Sicher, aber dann müssen Sie mit dem Namenskonflikt umgehen. Der Vorteil lokaler Geltungsbereiche besteht darin, dass sie dies vermeiden. Natürlich ist die Verwendung einer lokalen Aufzählung auch nicht kugelsicher: Wenn ein globales #define FIELD_WIDTH in etwas anderes umschreibt, sagen wir 20, würde die Aufzählung umgeschrieben werden `enum {20 = 10};` Wenn die globale und die lokale Definition von FIELD_WIDTH Aufzählungen sind, existieren beide Definitionen jedoch nebeneinander (die lokale Definition überschattet die globale). (Sehen eetimes.com/discussion/programming-pointers/4023879/… für weitere Informationen zu diesem Thema.

    – Jochen Walter

    26. Oktober 2010 um 19:59 Uhr


Dafür gibt es einen ganz handfesten Grund: const in C bedeutet nicht, dass etwas konstant ist. Es bedeutet nur, dass eine Variable schreibgeschützt ist.

An Stellen, an denen der Compiler eine echte Konstante benötigt (z. B. für Array-Größen für Nicht-VLA-Arrays), verwendet man a const variabel, wie z fieldWidth ist einfach nicht möglich.

  • +1 für die richtige Antwort unter einem Meer falscher Antworten von C++-Programmierern, die C nicht kennen.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Oktober 2010 um 13:59 Uhr

  • @C. Ross: Konsistenz. Alle manifesten Konstanten werden normalerweise mit definiert #defines. const wird nur verwendet, um eine Nur-Lese-Variable (Zugriffspfad auf eine) anzuzeigen. Ich weiss, const in C ist einfach nur kaputt 🙂

    – Bart van Ingen Schenau

    26. Oktober 2010 um 14:16 Uhr

  • Sie können nicht so etwas wie const int size 4 sagen; und dann später char str[size]?

    Benutzer379888

    27. Oktober 2010 um 11:29 Uhr

  • @fahad: Nicht in C89. In C99 können Sie dies für eine variable automatische Speicherdauer tun, aber es ist technisch gesehen ein VLA.

    – Café

    27. Oktober 2010 um 12:01 Uhr

  • @Exception: C und C++ sind sehr unterschiedliche Sprachen in ihrer Behandlung von const. In C++, const kann für richtige Konstanten verwendet werden, in C nicht.

    – Bart van Ingen Schenau

    28. Oktober 2010 um 9:54 Uhr

Benutzeravatar von Vovanium
Vovanium

Sie sind anders.

const ist nur ein Qualifizierer, der besagt, dass eine Variable zur Laufzeit nicht geändert werden kann. Aber alle anderen Merkmale der Variablen bleiben bestehen: Sie hat Speicher zugewiesen, und dieser Speicher kann adressiert werden. Der Code behandelt es also nicht nur als Literal, sondern verweist auf die Variable, indem er auf den angegebenen Speicherort zugreift (außer wenn dies der Fall ist static const, dann kann es wegoptimiert werden) und seinen Wert zur Laufzeit laden. Und als const Variable Speicherplatz zugewiesen hat, wenn Sie sie zu einem Header hinzufügen und in mehrere C-Quellen einschließen, erhalten Sie einen Verknüpfungsfehler “Mehrere Symboldefinition”, es sei denn, Sie markieren sie als extern. Und in diesem Fall kann der Compiler den Code nicht gegen seinen tatsächlichen Wert optimieren (es sei denn, die globale Optimierung ist aktiviert).

#define ersetzt einfach einen Namen durch seinen Wert. Außerdem ein #define‘d-Konstante kann im Präprozessor verwendet werden: Sie können sie mit verwenden #ifdef um eine bedingte Kompilierung basierend auf seinem Wert durchzuführen, oder verwenden Sie den Stringisierungsoperator # um einen String mit seinem Wert zu erhalten. Und da der Compiler seinen Wert zur Kompilierzeit kennt, kann er den Code basierend auf diesem Wert optimieren.

Zum Beispiel:

#define SCALE 1

...

scaled_x = x * SCALE;

Wann SCALE ist definiert als 1 der Compiler kann die Multiplikation eliminieren, da er das weiß x * 1 == xdoch wenn SCALE ist ein (extern) const, muss Code generiert werden, um den Wert abzurufen und die Multiplikation durchzuführen, da der Wert erst in der Verknüpfungsphase bekannt ist. (extern wird benötigt, um die Konstante aus mehreren Quelldateien zu verwenden.)

Ein näheres Äquivalent zur Verwendung #define verwendet Aufzählungen:

enum dummy_enum {
   constant_value = 10010
};

Dies ist jedoch auf ganzzahlige Werte beschränkt und hat keine Vorteile von #defineist also nicht weit verbreitet.

const ist nützlich, wenn Sie einen konstanten Wert aus einer Bibliothek importieren müssen, in der er kompiliert wurde. Oder wenn er mit Zeigern verwendet wird. Oder wenn es sich um ein Array konstanter Werte handelt, auf die über einen variablen Indexwert zugegriffen wird. Andernfalls, const hat keine Vorteile gegenüber #define.

  • +1 für die Erwähnung enum als Alternative – das sollte viel öfter verwendet werden. Ein großer Vorteil ist, dass das Symbol dem Debugger zur Verfügung steht.

    – Jonathan Leffler

    26. Oktober 2010 um 17:02 Uhr

  • Ich würde eher denken, dass es ein Debugger-Nachteil ist, nicht in der Lage zu sein, Definitionen zu verwenden, als ein Vorteil von Enum, um im Debugger verwendet werden zu können.

    – Vovanium

    26. Oktober 2010 um 18:56 Uhr

  • Und der Vorteil von #define Über enum ist, dass Sie können #ifdef um seine Anwesenheit zu testen oder seinen Wert zu nutzen #ifwas es viel nützlicher macht, Entscheidungen zur Bauzeit zu steuern oder Funktionen anzubieten, die auf einigen Plattformen vorhanden sein können, auf anderen jedoch nicht.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Oktober 2010 um 19:27 Uhr

  • Neuere Versionen von gdb/gcc tun unterstützen den Einsatz von #define Konstanten im Debugger (ich denke die -gdb3 Flag muss zur Kompilierzeit an gcc übergeben werden, um dies zu ermöglichen).

    – Psmärchen

    3. Dezember 2010 um 14:21 Uhr


  • Der Teil über die Optimierung gilt nicht für Compiler, die Link-Time-Optimierung durchführen.

    – Etienne

    30. August 2014 um 15:37 Uhr

Der Grund dafür ist, dass Sie meistens eine Konstante wollen, nicht eine const-qualifizierte Variable. Die beiden sind in der C-Sprache nicht im Entferntesten gleich. Beispielsweise sind Variablen nicht als Teil von Initialisierern für gültig static-storage-duration-Objekte als Nicht-VLA-Array-Dimensionen (z. B. die Größe eines Arrays in einer Struktur oder eines beliebigen Arrays vor C99).

  • Irgendein anderer Fall von Nicht-VLA-Array in C99 abgesehen von “Array in einer Struktur”?

    – Bitte helfen

    10. März 2015 um 19:43 Uhr

  • Arrays mit statischer Speicherdauer. Zusammengesetzte Literal-Arrays. Array-Typen verwendet in typedef mit Dateibereich. Vielleicht andere.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    11. März 2015 um 0:36 Uhr

Erweitern Sie die Antwort von R ein wenig: fieldWidth ist kein ständiger Ausdruck; es ist ein const-qualifizierte Variable. Es ist Wert wird erst zur Laufzeit erstellt und kann daher nicht verwendet werden, wenn ein konstanter Ausdruck zur Kompilierzeit erforderlich ist (z. B. in einer Array-Deklaration oder einer Case-Bezeichnung in einer switch Erklärung usw.).

Vergleichen Sie mit dem Makro FIELD_WIDTHdie nach der Vorverarbeitung zum konstanten Ausdruck erweitert wird 10; dieser Wert ist zur Kompilierzeit bekannt, sodass es für Array-Dimensionen, Fallbeschriftungen usw. verwendet werden kann.

Um die Antwort von R. und Bart zu ergänzen: Es gibt nur eine Möglichkeit, symbolische Kompilierzeitkonstanten in C zu definieren: Enumerationstypkonstanten. Der Standard schreibt vor, dass diese vom Typ sind int. Ich persönlich würde dein Beispiel so schreiben

enum { fieldWidth = 10 };

Aber ich denke, da gehen die Geschmäcker unter C-Programmierern sehr auseinander.

Benutzeravatar von CashCow
Goldesel

Obwohl ein const int nicht immer angemessen ist, funktioniert ein enum normalerweise als Ersatz für #define, wenn Sie etwas als ganzzahligen Wert definieren. Das ist eigentlich meine Präferenz in einem solchen Fall.

enum { FIELD_WIDTH = 16384 };
char buf[FIELD_WIDTH];

In C++ ist dies ein großer Vorteil, da Sie Ihre Aufzählung in einer Klasse oder einem Namensraum eingrenzen können, während Sie ein #define nicht eingrenzen können.

In C haben Sie keine Namespaces und können kein Enum innerhalb einer Struktur erfassen, und Sie sind sich nicht einmal sicher, ob Sie die Typsicherheit erhalten, daher kann ich keinen großen Vorteil erkennen, obwohl mich vielleicht ein C-Programmierer darauf hinweisen wird .

Benutzeravatar von Shlomi Loubaton
Shlomi Loubaton

Laut K&R (2. Auflage, Seite 211) sind die “const- und volatile-Eigenschaften neu beim ANSI-Standard”. Dies kann bedeuten, dass wirklich alter ANSI-Code diese Schlüsselwörter überhaupt nicht hatte, und es ist wirklich nur eine Frage der Tradition. Darüber hinaus besagt es, dass ein Compiler Versuche erkennen sollte, konstante Variablen zu ändern, aber abgesehen davon, dass er diese Qualifizierer ignorieren kann. Ich denke, es bedeutet, dass einige Compiler Code, der const-Variable enthält, möglicherweise nicht optimieren, um als Zwischenwert im Maschinencode dargestellt zu werden (wie es #define tut), und dies kann zusätzliche Zeit für den Zugriff auf weitem Speicher kosten und die Leistung beeinträchtigen.

  • +1 für das Zitieren von K&R, aber -1 für die Antwort, dass es eher um Optimierung als um Sprachanforderungen geht. Netto 0.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Oktober 2010 um 15:19 Uhr

  • Nein, es impliziert, dass const und volatile vom ANSI-Standard C eingeführt wurden. Die zweite Ausgabe von K&R wurde tatsächlich veröffentlicht, bevor der Standard ratifiziert wurde.

    – JeremyP

    26. Oktober 2010 um 15:21 Uhr

  • Viele C-Programmierer verwenden strchr statt nach einem Zeichen zu suchen strtof Weil strtof wurde erst C99 hinzugefügt.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Oktober 2010 um 19:30 Uhr

1421390cookie-checkWarum verwenden die meisten C-Entwickler define statt const? [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy