Dies ist eine ausgezeichnete Praxis.
Durch das Erstellen von Variablen in Schleifen stellen Sie sicher, dass deren Gültigkeitsbereich auf die Schleife beschränkt ist. Es kann nicht außerhalb der Schleife referenziert oder aufgerufen werden.
Diesen Weg:
Wenn der Name der Variablen etwas "generisch" ist (wie "i"), besteht kein Risiko, ihn irgendwo später in Ihrem Code mit einer anderen Variablen mit demselben Namen zu mischen (kann auch mithilfe der -Wshadow
Warnanweisung in GCC verringert werden ).
Der Compiler weiß, dass der Variablenbereich auf innerhalb der Schleife beschränkt ist, und gibt daher eine ordnungsgemäße Fehlermeldung aus, wenn auf die Variable versehentlich an anderer Stelle verwiesen wird.
Last but not least kann eine bestimmte dedizierte Optimierung vom Compiler effizienter durchgeführt werden (vor allem Registerzuordnung), da er weiß, dass die Variable nicht außerhalb der Schleife verwendet werden kann. Beispielsweise muss das Ergebnis nicht für eine spätere Wiederverwendung gespeichert werden.
Kurz gesagt, Sie haben Recht, es zu tun.
Beachten Sie jedoch, dass die Variable ihren Wert zwischen den einzelnen Schleifen nicht beibehalten soll . In diesem Fall müssen Sie es möglicherweise jedes Mal initialisieren. Sie können auch einen größeren Block erstellen, der die Schleife umfasst, deren einziger Zweck darin besteht, Variablen zu deklarieren, deren Wert von einer Schleife zur anderen beibehalten werden muss. Dies schließt typischerweise den Schleifenzähler selbst ein.
{
int i, retainValue;
for (i=0; i<N; i++)
{
int tmpValue;
/* tmpValue is uninitialized */
/* retainValue still has its previous value from previous loop */
/* Do some stuff here */
}
/* Here, retainValue is still valid; tmpValue no longer */
}
Zu Frage 2: Die Variable wird beim Aufruf der Funktion einmal zugewiesen. Aus Sicht der Zuordnung entspricht dies (fast) der Deklaration der Variablen zu Beginn der Funktion. Der einzige Unterschied ist der Umfang: Die Variable kann nicht außerhalb der Schleife verwendet werden. Es ist sogar möglich, dass die Variable nicht zugewiesen wird, sondern nur ein freier Steckplatz (von einer anderen Variablen, deren Gültigkeitsbereich beendet wurde) erneut verwendet.
Mit dem eingeschränkten und präziseren Umfang kommen genauere Optimierungen. Noch wichtiger ist jedoch, dass Ihr Code sicherer wird und weniger Zustände (dh Variablen) beim Lesen anderer Teile des Codes berücksichtigt werden müssen.
Dies gilt auch außerhalb eines if(){...}
Blocks. In der Regel anstelle von:
int result;
(...)
result = f1();
if (result) then { (...) }
(...)
result = f2();
if (result) then { (...) }
es ist sicherer zu schreiben:
(...)
{
int const result = f1();
if (result) then { (...) }
}
(...)
{
int const result = f2();
if (result) then { (...) }
}
Der Unterschied mag geringfügig erscheinen, insbesondere bei einem so kleinen Beispiel. Bei einer größeren Codebasis hilft dies jedoch: Jetzt besteht kein Risiko mehr, einen result
Wert von f1()
zu f2()
Block zu transportieren. Jedes result
ist streng auf seinen eigenen Umfang beschränkt, wodurch seine Rolle genauer wird. Aus Sicht der Rezensenten ist es viel schöner, da er weniger Zustandsvariablen mit großer Reichweite hat, über die er sich Sorgen machen und die er verfolgen muss.
Sogar der Compiler wird besser helfen: vorausgesetzt, dass in Zukunft nach einer fehlerhaften Codeänderung result
nicht richtig mit initialisiert wird f2()
. Die zweite Version weigert sich einfach zu arbeiten und gibt beim Kompilieren eine eindeutige Fehlermeldung aus (viel besser als zur Laufzeit). Die erste Version wird nichts erkennen, das Ergebnis von f1()
wird einfach ein zweites Mal getestet und für das Ergebnis von verwirrt f2()
.
Ergänzende Information
Das Open-Source-Tool CppCheck (ein statisches Analysetool für C / C ++ - Code) bietet einige hervorragende Hinweise zum optimalen Umfang von Variablen.
Antwort auf einen Kommentar zur Zuordnung: Die obige Regel gilt für C, gilt jedoch möglicherweise nicht für einige C ++ - Klassen.
Für Standardtypen und -strukturen ist die Größe der Variablen zum Zeitpunkt der Kompilierung bekannt. In C gibt es keine "Konstruktion", daher wird der Platz für die Variable einfach dem Stapel zugewiesen (ohne Initialisierung), wenn die Funktion aufgerufen wird. Aus diesem Grund fallen beim Deklarieren der Variablen innerhalb einer Schleife Kosten von "Null" an.
Für C ++ - Klassen gibt es jedoch diese Konstruktorsache, über die ich viel weniger weiß. Ich denke, die Zuweisung wird wahrscheinlich nicht das Problem sein, da der Compiler klug genug sein wird, um denselben Speicherplatz wiederzuverwenden, aber die Initialisierung wird wahrscheinlich bei jeder Schleifeniteration stattfinden.