it-swarm-eu.dev

Warum eine Variable in einer Zeile deklarieren und in der nächsten zuweisen?

Ich sehe oft in C- und C++ - Code die folgende Konvention:

some_type val;
val = something;

some_type *ptr = NULL;
ptr = &something_else;

anstatt

some_type val = something;
some_type *ptr = &something_else;

Ich nahm anfangs an, dass dies eine Gewohnheit war, die von den Tagen übrig geblieben war, als Sie alle lokalen Variablen am oberen Rand des Bereichs deklarieren mussten. Aber ich habe gelernt, die Gewohnheiten erfahrener Entwickler nicht so schnell zu verwerfen. Gibt es also einen guten Grund, in einer Zeile zu deklarieren und anschließend zuzuweisen?

102

C.

In C89 stehen alle Deklarationen mussten sein am Anfang eines Gültigkeitsbereichs ({ ... }), aber diese Anforderung wurde schnell gelöscht (zuerst mit Compiler-Erweiterungen und später mit dem Standard).

C++

Diese Beispiele sind nicht gleich. some_type val = something; ruft den Kopierkonstruktor auf, während val = something; ruft den Standardkonstruktor und dann das operator= Funktion. Dieser Unterschied ist oft kritisch.

Gewohnheiten

Einige Leute bevorzugen es, Variablen zuerst zu deklarieren und später zu definieren, falls sie ihren Code später mit den Deklarationen an einer Stelle und der Definition an einer anderen Stelle neu formatieren.

In Bezug auf die Zeiger haben einige Leute nur die Angewohnheit, jeden Zeiger auf NULL oder nullptr zu initialisieren, unabhängig davon, was sie mit diesem Zeiger tun.

92
orlp

Sie haben Ihre Fragen C und C++ gleichzeitig markiert, während die Antwort in diesen Sprachen erheblich unterschiedlich ist.

Erstens ist der Wortlaut des Titels Ihrer Frage falsch (oder genauer gesagt für die Frage selbst irrelevant). In beiden Beispielen lautet die Variable deklariert und definiert gleichzeitig in einer Zeile. Der Unterschied zwischen Ihren Beispielen besteht darin, dass im ersten Beispiel die Variablen entweder nicht initialisiert oder initialisiert mit einem Dummy-Wert belassen werden und dann zugewiesen a sinnvoller Wert später. Im zweiten Beispiel sind die Variablen sofort initialisiert.

Zweitens sind diese beiden Konstrukte in der C++ - Sprache, wie @nightcracker in seiner Antwort feststellte, semantisch unterschiedlich. Der erste basiert auf der Initialisierung, der zweite auf der Zuweisung. In C++ sind diese Operationen überladbar und können daher möglicherweise zu unterschiedlichen Ergebnissen führen (obwohl man feststellen kann, dass es keine gute Idee ist, nicht äquivalente Überladungen von Initialisierung und Zuweisung zu erzeugen).

In der ursprünglichen Standardsprache C (C89/90) ist es unzulässig, Variablen in der Mitte des Blocks zu deklarieren. Aus diesem Grund werden möglicherweise Variablen am Anfang des Blocks als nicht initialisiert (oder mit Dummy-Werten initialisiert) deklariert und dann als sinnvoll zugewiesen Werte später, wenn diese aussagekräftigen Werte verfügbar werden.

In der Sprache C99 ist es in Ordnung, Variablen in der Mitte des Blocks zu deklarieren (genau wie in C++). Dies bedeutet, dass der erste Ansatz nur in bestimmten Situationen erforderlich ist, in denen der Initialisierer zum Zeitpunkt der Deklaration nicht bekannt ist. (Dies gilt auch für C++).

27
AnT

Ich denke, es ist eine alte Gewohnheit, die aus Zeiten der "lokalen Deklaration" übrig geblieben ist. Und deshalb als Antwort auf Ihre Frage: Nein, ich glaube nicht, dass es einen guten Grund gibt. Ich mache es nie selbst.

13
CornflakesDK

Ich sagte etwas darüber in meine Antwort bis eine Frage von Helium .

Grundsätzlich sage ich, es ist eine visuelle Hilfe, um leicht zu erkennen, was sich geändert hat.

if (a == 0) {
    struct whatever *myobject = 0;
    /* did `myobject` (the pointer) get assigned?
    ** or was it `*myobject` (the struct)? */
}

und

if (a == 0) {
    struct whatever *myobject;
    myobject = 0;
    /* `myobject` (the pointer) got assigned */
}
4
pmg

Die anderen Antworten sind ziemlich gut. In C gibt es eine Geschichte dazu. In C++ gibt es den Unterschied zwischen einem Konstruktor und einem Zuweisungsoperator.

Ich bin überrascht, dass niemand den zusätzlichen Punkt erwähnt: Das Trennen von Deklarationen von der Verwendung einer Variablen kann manchmal viel besser lesbar sein.

Visuell gesehen sind beim Lesen von Code die profaneren Artefakte wie die Typen und Namen von Variablen nicht das, was Sie anspricht. Es ist das aussagen dass Sie normalerweise am meisten interessiert sind, die meiste Zeit damit verbringen, zu starren, und daher besteht die Tendenz, einen Blick über den Rest zu werfen.

Wenn ich einige Typen, Namen und Zuweisungen habe, die alle auf engstem Raum stattfinden, ist dies eine gewisse Informationsüberflutung. Außerdem bedeutet dies, dass in dem Raum, über den ich normalerweise schaue, etwas Wichtiges vor sich geht.

Es mag etwas kontraintuitiv erscheinen zu sagen, aber dies ist ein Fall, in dem es besser sein kann, wenn Ihre Quelle mehr vertikalen Raum einnimmt. Ich sehe dies als eine Art Grund, warum Sie keine vollgepackten Zeilen schreiben sollten, die verrückte Mengen an Zeigerarithmetik und Zuweisung in einem engen vertikalen Raum ausführen - nur weil die Sprache Sie mit solchen Dingen davonkommen lässt, heißt das nicht, dass Sie es tun sollten es die ganze Zeit. :-)

4
asveikau

In C war dies die Standardpraxis, da Variablen zu Beginn der Funktion deklariert werden mussten, anders als in C++, wo sie an einer beliebigen Stelle im Funktionskörper deklariert werden konnten, um danach verwendet zu werden. Zeiger wurden auf 0 oder NULL gesetzt, da nur sichergestellt wurde, dass der Zeiger auf keinen Müll zeigte. Ansonsten gibt es keinen signifikanten Vorteil, den ich mir vorstellen kann, der jeden dazu zwingt, so etwas zu tun.

2
Vite Falcon

Vorteile für die Lokalisierung von Variablendefinitionen und deren sinnvolle Initialisierung:

  • wenn Variablen gewöhnlich einen aussagekräftigen Wert zugewiesen bekommen, wenn sie zum ersten Mal im Code erscheinen (eine andere Perspektive auf dasselbe: Sie verzögern ihr Erscheinen, bis ein aussagekräftiger Wert verfügbar ist), gibt es keine Chance, dass sie versehentlich verwendet werden mit einem bedeutungsloser oder nicht initialisierter Wert (was leicht passieren kann, wenn eine Initialisierung aufgrund von bedingten Anweisungen, Kurzschlussauswertung, Ausnahmen usw. versehentlich umgangen wird)

  • kann mehr sein effizient

    • vermeidet den Aufwand für das Festlegen des Anfangswertes (Standardkonstruktion oder Initialisierung auf einen Sentinel-Wert wie NULL).
    • operator= kann manchmal weniger effizient sein und ein temporäres Objekt erfordern
    • manchmal (besonders für Inline-Funktionen) Der Optimierer kann einige/alle Ineffizienzen beseitigen

  • durch Minimieren des Gültigkeitsbereichs von Variablen wird wiederum Durchschnitt Anzahl von Variablen gleichzeitig im Gültigkeitsbereich: this minimiert

    • macht es einfacher mental zu verfolgen die Variablen im Gültigkeitsbereich, die Ausführungsabläufe und Anweisungen, die diese Variablen beeinflussen könnten, und den Import ihres Werts
    • zumindest für einige komplexe und undurchsichtige Objekte ist dies reduziert den Ressourcenverbrauch (Heap, Threads, gemeinsamer Speicher, Deskriptoren) des Programms
  • manchmal prägnanter, da Sie den Variablennamen in einer Definition nicht wiederholen als in einer anfänglichen sinnvollen Zuweisung

  • erforderlich für bestimmte Typen wie Referenzen und wenn das Objekt const sein soll

Argumente zum Gruppieren von Variablendefinitionen:

  • manchmal ist es bequem und/oder prägnant, um den Typ einer Reihe von Variablen herauszufiltern:

    the_same_type v1, v2, v3;

    (Wenn der Grund nur darin besteht, dass der Typname zu lang oder zu komplex ist, kann ein typedef manchmal besser sein)

  • manchmal ist es wünschenswert, Variablen unabhängig von ihrer Verwendung zu gruppieren, um die Menge der Variablen (und Typen) hervorzuheben, die an einer Operation beteiligt sind:

    type v1;
    type v2;type v3;

    Dies unterstreicht die Gemeinsamkeit des Typs und erleichtert das Ändern der Schrift, während die Variable pro Zeile beibehalten wird, was das Kopieren und Einfügen erleichtert. // kommentieren etc ..

Wie es beim Programmieren häufig der Fall ist, kann eine Praxis in den meisten Situationen einen klaren empirischen Nutzen haben, während die andere Praxis in einigen Fällen wirklich überwältigend besser sein kann.

2
Tony