Ein Block ist eine Liste von Anweisungen, die ausgeführt werden sollen. Beispiele für das Auftauchen von Blöcken in C sind Anweisungen nach einer Weile und if-Anweisungen
while( boolean expression)
statement OR block
if (boolean expression)
statement OR block
Mit C kann ein Block auch in einem Block verschachtelt werden. Ich kann dies verwenden, um Variablennamen wiederzuverwenden. Angenommen, ich mag 'x' wirklich.
int x = 0;
while (x < 10)
{
{
int x = 5;
printf("%d",x)
}
x = x+1;
}
druckt die Nummer 5 zehnmal. Ich denke, ich könnte Situationen sehen, in denen es wünschenswert ist, die Anzahl der Variablennamen niedrig zu halten. Vielleicht in Makro-Erweiterung. Ich kann jedoch keinen schwerwiegenden Grund dafür erkennen, diese Funktion zu benötigen. Kann mir jemand helfen, die Verwendung dieser Funktion zu verstehen, indem er einige Redewendungen angibt, wo sie verwendet wird?
Antworten:
Die Idee ist nicht, die Anzahl der Variablennamen gering zu halten oder auf andere Weise die Wiederverwendung von Namen zu fördern, sondern den Bereich der Variablen einzuschränken. Wenn Sie haben:
dann ist der Umfang von
y
auf den Block beschränkt, was bedeutet, dass Sie ihn entweder vor oder nach dem Block vergessen können. Dies wird am häufigsten in Verbindung mit Schleifen und Bedingungen verwendet. Sie sehen es auch häufiger in C-ähnlichen Sprachen wie C ++, wo eine Variable, die den Gültigkeitsbereich verlässt, zerstört wird.quelle
Denn in früheren Tagen von C konnten neue Variablen nur in einem neuen Block deklariert werden.
Auf diese Weise können Programmierer mitten in einer Funktion neue Variablen einfügen, ohne diese zu verlieren und die Stapelverwendung zu minimieren.
Mit heutigen Optimierern ist dies nutzlos und ein Zeichen dafür, dass Sie in Betracht ziehen müssen, den Block in seiner eigenen Funktion zu extrahieren.
In einer switch-Anweisung ist es hilfreich, die Fälle in eigene Blöcke einzuschließen, um eine doppelte Deklaration zu vermeiden.
In C ++ ist es beispielsweise sehr nützlich für RAII-Sperrwächter und um sicherzustellen, dass die Destruktoren die Freigabesperre ausführen, wenn die Ausführung den Gültigkeitsbereich verlässt und andere Aufgaben außerhalb des kritischen Abschnitts ausgeführt werden.
quelle
Ich würde es nicht als "willkürliche" Blöcke betrachten. Es ist keine Funktion, die für Entwickler so wichtig ist, aber die Art und Weise, wie C Blöcke verwendet, ermöglicht die Verwendung desselben Blockkonstrukts an mehreren Stellen mit derselben Semantik. Ein Block (in C) ist ein neuer Gültigkeitsbereich, und Variablen, die ihn verlassen, werden entfernt. Dies ist unabhängig von der Verwendung des Blocks einheitlich.
In anderen Sprachen ist dies nicht der Fall. Dies hat den Vorteil, weniger Missbrauch zuzulassen, wie Sie zeigen, aber den Nachteil, dass sich Blöcke je nach Kontext unterschiedlich verhalten.
Ich habe selten eigenständige Blöcke gesehen, die in C oder C ++ verwendet wurden - oft, wenn es eine große Struktur oder ein Objekt gibt, das eine Verbindung oder etwas darstellt, dessen Zerstörung Sie erzwingen möchten. In der Regel ist dies ein Hinweis darauf, dass Ihre Funktion zu viele Aufgaben ausführt und / oder zu lang ist.
quelle
Man muss erkennen, dass Programmierprinzipien, die jetzt offensichtlich zu sein scheinen, nicht immer so waren. C Best Practices hängen stark davon ab, wie alt Ihre Beispiele sind. Als C zum ersten Mal eingeführt wurde, galt es als zu ineffizient, Ihren Code in kleine Funktionen zu unterteilen. Dennis Ritchie log im Grunde genommen und sagte, dass Funktionsaufrufe in C wirklich effizient waren (sie waren nicht zu der Zeit), was die Leute dazu brachte, sie mehr zu benutzen, obwohl C-Programmierer irgendwie nie wirklich an einer Kultur der vorzeitigen Optimierung vorbei kamen.
Es ist auch heute noch eine gute Programmierpraxis, den Umfang Ihrer Variablen so gering wie möglich zu halten. Heutzutage tun wir dies in der Regel durch das Erstellen einer neuen Funktion. Wenn Funktionen jedoch als teuer eingestuft werden, ist das Einfügen eines neuen Blocks eine logische Möglichkeit, Ihren Gültigkeitsbereich ohne den Aufwand eines Funktionsaufrufs einzuschränken.
Ich habe jedoch vor über 20 Jahren mit dem Programmieren in C begonnen, als Sie alle Variablen an der Spitze eines Bereichs deklarieren mussten, und ich erinnere mich nicht, dass Variablenschattierungen wie diese jemals als guter Stil angesehen wurden. Wie in einer switch-Anweisung in zwei Blöcken nacheinander neu deklarieren, ja, aber nicht schattieren. Vielleicht, wenn die Variable bereits verwendet wurde und der spezifische Name für die API, die Sie aufrufen, wie zum Beispiel
dest
undsrc
instrcpy
, sehr idiomatisch war .quelle
Willkürliche Blöcke sind nützlich, um Zwischenvariablen einzuführen, die nur in speziellen Fällen einer Berechnung verwendet werden.
Dies ist ein gängiges Muster im wissenschaftlichen Rechnen, bei dem numerische Verfahren typischerweise:
Aufgrund des zweiten Punktes ist es sinnvoll, temporäre Variablen mit begrenztem Gültigkeitsbereich einzuführen, was durch die Verwendung eines beliebigen Blocks oder durch die Einführung einer Hilfsfunktion erreicht wird.
Während die Einführung einer Hilfsfunktion wie ein Kinderspiel oder eine bewährte Methode aussieht, die man blindlings befolgen sollte, hat dies in dieser speziellen Situation nur geringe Vorteile .
Da es viele Parameter und Zwischengrößen gibt, wollen wir eine Struktur einführen, um diese an die Hilfsfunktion weiterzugeben.
Da wir jedoch konsequent mit unseren Praktiken umgehen wollen, werden wir nicht nur eine Hilfsfunktion einführen, sondern mehrere. Ob wir also Ad-hoc-Strukturen einführen, die Parameter für jede Funktion übermitteln, die viel Code-Overhead zum Hin- und Herbewegen von Parametern verursachen, oder ob wir eine Struktur für alle Arbeitsblätter einführen , die alle unsere Variablen enthält, aber so aussieht Ein Grabpack von Bits ohne Konsistenz, bei dem zu jeder Zeit nur die Hälfte der Parameter eine interessante Bedeutung hat.
Daher sind diese Hilfsstrukturen in der Regel umständlich und erfordern die Wahl zwischen Code-Bloat oder die Einführung einer Abstraktion, deren Umfang zu weit gefasst ist, und schwächen die Bedeutung des Programms, anstatt es zu erweitern .
Die Einführung von Hilfsfunktionen könnte das Unit-Testen des Programms vereinfachen, indem eine feinere Testgranularität eingeführt wird. Die Kombination von Unit-Testing für nicht so einfache Prozeduren und Regressionstests in Form von Vergleichen (mit einer bestimmten Anzahl von numerischen Spuren der Prozeduren) ist jedoch ebenso gut .
quelle
Im Allgemeinen führt die Wiederverwendung von Variablennamen auf diese Weise zu zu großer Verwirrung bei zukünftigen Lesern Ihres Codes. Es ist besser, die innere Variable einfach etwas anderes zu nennen. Tatsächlich verbietet die C # -Sprache die Verwendung von Variablen auf diese Weise.
Ich konnte sehen, wie die Verwendung von verschachtelten Blöcken in Makro-Erweiterungen nützlich wäre, um Kollisionen bei der Benennung von Variablen zu verhindern.
quelle
Es ist für das Scoping von Dingen gedacht, die auf dieser Ebene normalerweise keinen Gültigkeitsbereich haben. Dies ist äußerst selten und im Allgemeinen ist Refactoring eine bessere Wahl, aber ich bin in der Vergangenheit ein- oder zweimal in switch-Anweisungen darauf gestoßen:
Wenn Sie Wartungsarbeiten in Betracht ziehen, sollten Sie beim Refactoring alle Implementierungen in einer Reihe haben, sofern jede nur ein paar Zeilen lang ist. Es kann einfacher sein, sie alle zusammen zu haben, als eine Liste von Funktionsnamen.
Wenn ich mich recht erinnere, handelte es sich bei den meisten Fällen um geringfügige Abweichungen desselben Codes - mit der Ausnahme, dass einer mit einem anderen identisch war, nur mit zusätzlicher Vorverarbeitung. Ein Schalter stellte die einfachste Form für den Code dar, und der zusätzliche Gültigkeitsbereich ermöglichte die Verwendung zusätzlicher lokaler Variablen, um die er sich und weitere Fälle nicht kümmern mussten (z. B. Variablennamen, die sich versehentlich mit denen überschneiden, die vor dem Schalter definiert wurden, aber später verwendet).
Beachten Sie, dass die switch-Anweisung einfach die Verwendung ist, auf die ich gestoßen bin. Ich bin mir sicher, dass es auch anderswo angewendet werden kann, aber ich kann mich nicht erinnern, dass sie so effektiv eingesetzt wurden.
quelle