Warum verbietet Pascal die Änderung des Zählers innerhalb des For-Blocks?

7

Liegt es daran, dass Pascal so entworfen wurde, oder gibt es irgendwelche Kompromisse?

Oder was sind die Vor- und Nachteile, um die Änderung des Zählers in einem For-Block zu verbieten oder nicht zu verbieten? IMHO, es ist wenig sinnvoll, den Zähler in einem For-Block zu ändern.

BEARBEITEN :
Könnten Sie ein Beispiel angeben, bei dem wir den Zähler im For-Block ändern müssen?

Es ist schwer zwischen wlikks Antwort und cartoonfox's Antwort zu wählen, da beide Antworten so nett sind. Cartoonfox analysiert das Problem vom Sprachaspekt aus, während Wallyk das Problem aus der Geschichte und der realen Welt analysiert aspect.Anyway, danke für all deine Antworten und ich möchte mich ganz herzlich bei Wallyk bedanken.

    
Jichao 15.01.2010, 13:40
quelle

7 Antworten

13

In der Programmiersprachentheorie (und in der Berechenbarkeitstheorie) WHILE- und FOR-Schleifen haben unterschiedliche theoretische Eigenschaften :

  • Eine WHILE-Schleife kann niemals enden (der Ausdruck könnte einfach TRUE sein)
  • die endliche Anzahl von Malen, die eine FOR-Schleife ausführen soll, soll bekannt sein, bevor sie mit der Ausführung beginnt. Sie sollten wissen, dass FOR-Schleifen immer enden.

Die in C vorhandene FOR-Schleife zählt technisch nicht als FOR-Schleife, weil Sie nicht unbedingt wissen, wie oft die Schleife iteriert, bevor sie ausgeführt wird. (d. h. Sie können den Schleifenzähler hacken, um ihn für immer auszuführen)

Die Klasse von Problemen, die Sie mit WHILE-Schleifen lösen können, ist strikt leistungsfähiger als die, die Sie mit der strikten FOR-Schleife in Pascal hätten lösen können.

Pascal ist so konzipiert, dass die Schüler zwei verschiedene Schleifenkonstrukte mit unterschiedlichen Recheneigenschaften haben . (Wenn Sie FOR für den C-Weg implementiert haben, wäre die FOR-Schleife nur eine alternative Syntax für while ...)

In streng theoretischen Begriffen sollten Sie den Zähler nie innerhalb einer for-Schleife ändern müssen. Wenn Sie damit durchkommen könnten, hätten Sie nur eine alternative Syntax für eine WHILE-Schleife .

In diesen CS-Skripten können Sie mehr über "while loop computability" und "for loop computability" erfahren: Ссылка

Eine weitere Eigenschaft ist, dass die Schleifenvariable nach der for-Schleife undefiniert ist. Dies erleichtert auch die Optimierung

    
daf 20.01.2010, 01:45
quelle
11

Pascal wurde zuerst für den CDC Cyber ​​implementiert - ein Mainframe der 1960er und 1970er Jahre - der, wie viele CPUs heute, eine ausgezeichnete sequenzielle Befehlsausführung, aber auch eine erhebliche Leistungseinbuße für Zweigstellen hatte. Diese und andere Eigenschaften der Cyber-Architektur haben wahrscheinlich Pascals Design von for loops stark beeinflusst.

Die Kurze Antwort bedeutet, dass die Zuweisung einer Schleifenvariablen einen zusätzlichen Schutzcode und eine fehlerhafte Optimierung für Schleifenvariablen erfordert, die normalerweise in 18-Bit-Indexregistern gut verarbeitet werden können. Zu dieser Zeit wurde die Software-Performance wegen der Kosten der Hardware und der Unfähigkeit, sie auf andere Weise zu beschleunigen, sehr geschätzt.

Lange Antwort

Die Control Data Corporation 6600-Familie, die den Cyber ​​enthält, ist eine RISC-Architektur, die 60-Bit-Zentralspeicherwörter verwendet, auf die 18-Bit-Adressen verweisen. Einige Modelle hatten eine (teure, daher unübliche) Option, die Compare-Move-Unit (CMU) zum direkten Adressieren von 6-Bit-Zeichenfeldern, aber ansonsten gab es keine Unterstützung für "Bytes" jeglicher Art. Da die CMU im Allgemeinen nicht gezählt werden konnte, wurde der meiste Cyber-Code für seine Abwesenheit generiert. Zehn Zeichen pro Wort waren das übliche Datenformat, bis die Unterstützung für Kleinbuchstaben einer vorläufigen 12-Bit-Zeichendarstellung wich.

Die Befehle sind 15 Bits oder 30 Bits lang, außer dass die CMU-Befehle effektiv 60 Bits lang sind. Also bis zu 4 Befehle in jedes Wort gepackt, oder zwei 30 Bit, oder ein Paar 15 Bit und ein 30 Bit. 30-Bit-Befehle können keine Wörter umfassen. Da Verzweigungsziele nur Wörter referenzieren können, sind Sprungziele wortausgerichtet.

Die Architektur hat keinen Stapel. Tatsächlich ist die Prozeduraufrufanweisung RJ intrinsisch nicht einspringend. RJ modifiziert das erste Wort der aufgerufenen Prozedur, indem ein Sprung zur nächsten Anweisung nach der Anweisung von RJ geschrieben wird. Aufgerufene Prozeduren kehren zum Aufrufer zurück, indem sie an ihren Anfang springen, der für die Rückkehrverknüpfung reserviert ist. Die Prozeduren beginnen mit dem zweiten Wort. Um die Rekursion zu implementieren, verwendeten die meisten Compiler eine Hilfsfunktion.

Die Registerdatei hat acht Instanzen von jeweils drei Arten von Registern, A0..A7 für die Adressenmanipulation, B0..B7 für die Indexierung und X0..X7 für die allgemeine Arithmetik. A- und B-Register sind 18 Bits; X-Register sind 60 Bits. Die Einstellung A1 bis A5 hat den Nebeneffekt, dass das entsprechende Register X1 bis X5 mit dem Inhalt der geladenen Adresse geladen wird. Setzen von A6 oder A7 schreibt die entsprechenden X6- oder X7-Inhalte in die Adresse, die in das A-Register geladen ist. A0 und X0 sind nicht verbunden. Die B-Register können in praktisch jedem Befehl als ein Wert zum Addieren oder Subtrahieren von irgendeinem anderen A-, B- oder X-Register verwendet werden. Daher sind sie ideal für kleine Zähler.

Für einen effizienten Code wird ein B-Register für Schleifenvariablen verwendet, da direkte Vergleichsbefehle an ihnen verwendet werden können (B2 & lt; 100 usw.); Vergleiche mit X-Registern sind auf Relationen zu Null beschränkt, so dass ein Vergleich eines X-Registers mit 100 beispielsweise das Subtrahieren von 100 und das Testen des Ergebnisses für weniger als Null usw. erfordert. Wenn eine Zuweisung an die Schleifenvariable erlaubt war, ein 60-Bit-Wert müsste vor der Zuordnung zum B-Register range-geprüft werden. Das ist ein wirklicher Ärger. Herr Wirth hat wahrscheinlich gedacht, dass sowohl der Aufwand als auch die Ineffizienz den Nutzen nicht wert sind - der Programmierer kann immer eine while oder repeat ... until Schleife in dieser Situation verwenden.

Zusätzliche Seltsamkeit

Mehrere Funktionen von Unique-to-Pascal beziehen sich direkt auf Aspekte des Cyber:

  • Das Schlüsselwort pack : Entweder ein einzelnes "Zeichen" verbraucht ein 60-Bit-Wort oder es sind zehn Zeichen pro Wort gepackt.
  • der (ungewöhnliche) alfa Typ: packed array [1..10] of char
  • intrinsische Prozeduren pack() und unpack() , um mit gepackten Zeichen umzugehen. Diese führen keine Transformation auf modernen Architekturen durch, nur Typumwandlung.
  • die Seltsamkeit von text files vs file of char
  • kein expliziter Newline-Charakter. Datensatzverwaltung wurde explizit mit writeln aufgerufen
  • Obwohl set of char sehr nützlich für CDCs war, wurde es auf vielen nachfolgenden 8-Bit-Maschinen aufgrund seiner übermäßigen Speicherbelegung (32-Byte-Variablen / Konstanten für 8-Bit-ASCII) nicht unterstützt. Im Gegensatz dazu könnte ein einzelnes Cyber-Wort den nativen 62-Zeichen-Satz verwalten, indem Newline und etwas anderes weggelassen wird.
  • vollständige Ausdrucksbewertung (im Gegensatz zu Verknüpfungen). Diese wurden nicht durch Springen und Setzen von Eins oder Null implementiert (wie es die meisten Codegeneratoren heute tun), sondern durch CPU-Befehle, die Boolesche Arithmetik implementieren.
wallyk 20.01.2010 07:03
quelle
7

Pascal wurde ursprünglich als Unterrichtssprache entwickelt, um blockorientierte Programmierung zu fördern. Kernighan (das K von K & amp; R) schrieb einen (verständlicherweise voreingenommenen) Aufsatz über Pascals Beschränkungen, Warum Pascal nicht meine bevorzugte Programmiersprache ist .

Das Verbot, das zu ändern, was Pascal die Steuervariable einer for -Schleife nennt, kombiniert mit dem Fehlen einer break -Anweisung bedeutet, dass es möglich ist zu wissen, wie oft der Schleifenkörper ist wird ausgeführt, ohne seinen Inhalt zu studieren.

Ohne eine break -Anweisung, und nicht in der Lage, die Steuervariable zu verwenden, nachdem die Schleife beendet wird, ist mehr eine Einschränkung, als die Steuervariable innerhalb der Schleife nicht ändern zu können, da einige String- und Array-Verarbeitungsalgorithmen davon abgehalten werden auf die "offensichtliche" Weise geschrieben werden.

Diese und andere Unterschiede zwischen Pascal und C spiegeln die verschiedenen Philosophien wider, mit denen sie ursprünglich entworfen wurden: Pascal, um ein Konzept des "richtigen" Designs durchzusetzen, C um mehr oder weniger alles zu erlauben, egal wie gefährlich es ist.

(Hinweis: Delphi hat jedoch eine Break -Anweisung sowie Continue und Exit , was wie return in C ist.)

Natürlich brauchen wir nicht , um die Steuervariable in einer for -Schleife ändern zu können, weil wir immer mit einer while -Schleife umschreiben können. Ein Beispiel in C, wo solch ein Verhalten verwendet wird, kann in K & amp; R Abschnitt 7.3 gefunden werden, wo eine einfache Version von printf() eingeführt wird. Der Code, der '%' Sequenzen innerhalb einer Formatzeichenfolge fmt verarbeitet, ist:

%Vor%

Obwohl ein Zeiger als Schleifenvariable verwendet wird, könnte er auch mit einem ganzzahligen Index in die Zeichenfolge geschrieben worden sein:

%Vor%     
P-Nuts 17.01.2010 17:50
quelle
3

Es kann einige Optimierungen (z. B. Schleifen-Abrollung) einfacher machen: Es ist keine komplizierte statische Analyse erforderlich, um zu bestimmen, ob das Schleifenverhalten vorhersehbar ist oder nicht.

    
dmckee 16.01.2010 03:13
quelle
1

Von For-Schleife

  

In einigen Sprachen (nicht C oder C ++)   Schleifenvariable ist innerhalb der   Umfang des Schleifenkörpers, mit irgendwelchen   versuchen, seinen Wert zu ändern   als semantischer Fehler betrachtet. Eine solche   Modifikationen sind manchmal a   Folge eines Programmierfehlers,   Das kann sehr schwierig sein   identifiziere dich einmal. Jedoch nur offen   Änderungen werden wahrscheinlich von entdeckt   der Compiler. Situationen, in denen die   Adresse der Schleifenvariablen wird übergeben   als ein Argument zu einer Subroutine machen es   sehr schwer zu überprüfen, weil die   Das Verhalten der Routine ist im Allgemeinen   Unerkennbar für den Compiler.

Das scheint also zu sein, damit Sie sich später nicht die Hand verbrennen.

    
Adriaan Stander 15.01.2010 13:45
quelle
1

Haftungsausschluss: Es ist Jahrzehnte her, dass ich PASCAL zum letzten Mal benutzt habe, daher ist meine Syntax möglicherweise nicht genau richtig.

Sie müssen sich daran erinnern, dass PASCAL das Kind von Nicklaus Wirth ist, und Wirth sorgte sich sehr stark um Zuverlässigkeit und Verständlichkeit, als er PASCAL (und all seine Nachfolger) entwarf.

Betrachten Sie das folgende Codefragment:

%Vor%

Beantworten Sie diese Fragen, ohne die Prozedur FOO zu betrachten: Wird diese Schleife jemals enden? Woher weißt du das? Wie oft wird Prozedur FOO in der Schleife aufgerufen? Woher weißt du das?

PASCAL verbietet das Ändern der Indexvariablen im Schleifenkörper, so dass es möglich ist, die Antworten auf diese Fragen zu kennen, und wissen, dass sich die Antworten nicht ändern werden, wenn sich die Prozedur FOO ändert.

    
John R. Strohm 17.01.2010 16:03
quelle
1

Es ist wahrscheinlich sicher, dass Pascal entworfen wurde, um die Modifikation eines for-Schleife-Index innerhalb der Schleife zu verhindern. Es ist erwähnenswert, dass Pascal keineswegs die einzige Programmiersprache ist, die Programmierer daran hindert, Fortran ist ein anderes Beispiel.

Es gibt zwei zwingende Gründe, eine Sprache so zu gestalten:

  1. Programme, insbesondere die for-Schleifen in ihnen, sind leichter zu verstehen und daher einfacher zu schreiben und zu modifizieren und zu verifizieren.
  2. Schleifen sind leichter zu optimieren, wenn der Compiler weiß, dass die Anzahl der Trips durch eine Schleife vor Eintritt in die Schleife und danach invariant festgelegt wird.

Für viele Algorithmen ist dieses Verhalten das erforderliche Verhalten; Aktualisieren aller Elemente in einem Array zum Beispiel. Wenn Speicher dient Pascal bietet auch Do-While-Loops und Wiederholungs-Loops. Die meisten, ich denke, Algorithmen, die in C-Stil-Sprachen mit Änderungen an der Loop-Index-Variable implementiert sind oder aus der Schleife ausbrechen, könnten genauso leicht mit diesen alternativen Formen der Schleife implementiert werden.

Ich habe mir den Kopf zerkratzt und keinen zwingenden Grund gefunden, eine Schleifenindexvariable innerhalb der Schleife zu ändern, aber ich habe das immer als schlechtes Design und die Wahl des richtigen Schleifenkonstrukts betrachtet als ein Element des guten Designs.

Grüße

Markieren

    
High Performance Mark 17.01.2010 18:42
quelle

Tags und Links