Wurde die Programmiersprache C bei der Veröffentlichung als einfache Sprache eingestuft?

151

Gegenwärtig wird C als niedrige Sprache betrachtet , aber in den 70er Jahren wurde es als niedrige Sprache angesehen? War der Begriff damals überhaupt gebräuchlich?

Viele beliebte höhere Sprachen gab es erst Mitte der 80er Jahre und darüber hinaus. Ich bin gespannt, ob und wie sich die Natur niedriger Niveaus im Laufe der Jahre verändert hat.

joeyfb
quelle
13
Als einen Datenpunkt haben mir einige Programmier-Mentoren um 1978 C als eine verherrlichte Assemblersprache beschrieben.
Ben Crowell
7
@BenCrowell Ich bin nicht sicher, was "verherrlicht" im Kontext Ihrer Aussage bedeutet, aber ich habe C als universelle (= plattformunabhängige) Assemblersprache bezeichnet .
Melebius
13
Interessanterweise gibt es den Fall, dass C keine Low-Level-Sprache ist und jetzt weniger als in den 70er Jahren, da die abstrakte Maschine von C weiter von der modernen Hardware entfernt ist als von der PDP-11.
Tom
5
Wenn Sie daran denken, möchten Sie vielleicht auch an den Ursprung denken - Unix ist in C geschrieben, c läuft unter Unix und kompiliert Unix mit anderen Plattformen. Alles, was zum Kompilieren von Unix nicht erforderlich war, war unnötiger Aufwand, und das Hauptziel von C bestand darin, das Schreiben / Portieren eines Compilers so einfach wie möglich zu gestalten. Zu diesem Zweck war es das GENAUE richtige Level, also denke ich nicht an C als High- oder Low-Level, sondern an ein Tool zum Portieren von Unix, das wie fast alle Unix-Tools extrem an viele Probleme anpassbar ist.
Bill K
4
Es ist erwähnenswert, dass
Prime

Antworten:

144

Um die historischen Aspekte der Frage zu beantworten:

Die Designphilosophie wird in der C-Programmiersprache von Brian Kernighan und C-Designer Dennis Ritchie erklärt, dem "K & R", von dem Sie vielleicht schon gehört haben. Das Vorwort zur ersten Ausgabe sagt

C ist keine "sehr hohe" Sprache, noch eine "große" ...

und die Einführung sagt

C ist eine relativ "einfache" Sprache ... C bietet keine Operationen, um direkt mit zusammengesetzten Objekten wie Zeichenketten, Mengen, Listen oder Arrays umzugehen. Es gibt keine Operationen, die ein ganzes Array oder einen ganzen String manipulieren ...

Die Liste wird eine Weile fortgesetzt, bevor der Text fortgesetzt wird:

Obwohl das Fehlen einiger dieser Merkmale wie ein schwerwiegender Mangel erscheint, hat es echte Vorteile, die Sprache auf eine bescheidene Größe zu beschränken.

(Ich habe nur die zweite Ausgabe von 1988, aber der Kommentar unten zeigt, dass der zitierte Text der gleiche ist wie in der ersten Ausgabe von 1978.)

Also, ja, die Begriffe "High Level" und "Low Level" waren damals gebräuchlich, aber C wurde entwickelt, um irgendwo im Spektrum dazwischen zu liegen. Es war möglich, Code in C zu schreiben, der auf Hardwareplattformen portierbar war, und dies war das Hauptkriterium dafür, ob eine Sprache zu dieser Zeit als hoch angesehen wurde. In C fehlten jedoch einige Merkmale, die für Hochsprachen charakteristisch waren, und dies war eine Entwurfsentscheidung zugunsten der Einfachheit.

Gatkin
quelle
42
Dies ist eine hervorragende Antwort! Nachprüfbare historische Beweise + Zeugnis eines Akteurs, der am besten über die Bedeutung von niedrigem und hohem Niveau in dem Zeitraum informiert ist, auf den sich das OP bezieht. Ich bestätige übrigens, dass die Zitate bereits in der Ausgabe von 1978 enthalten waren.
Christophe
157

Dies hängt von Ihrer Definition der Hochsprache und der Niedrigsprache ab. Bei der Entwicklung von C wurde alles, was über Assembler lag, als Hochsprache betrachtet. Das ist ein niedriger Balken, um zu löschen. Später verlagerte sich diese Terminologie zu einem Punkt, an dem manche heutzutage sogar Java als eine Sprache auf niedriger Ebene betrachten würden.

Selbst innerhalb der Hochsprachenlandschaft der 70er Jahre ist darauf hinzuweisen, dass C ein relativ niedriges Niveau aufweist. Die Sprache C ist im Grunde genommen B plus ein einfaches Typsystem, und B ist nicht viel mehr als eine bequeme prozedurale / strukturierte Syntaxschicht für die Assemblierung. Da das Typsystem über der nicht typisierten Sprache B nachgerüstet wird, können Sie an einigen Stellen Typanmerkungen weglassen und intwerden angenommen.

C verzichtet bewusst auf teure oder schwer zu implementierende Funktionen, die zu diesem Zeitpunkt bereits etabliert waren, wie z

  • automatische Speicherverwaltung
  • verschachtelte Funktionen oder Abschlüsse
  • grundlegende OOP oder Coroutinen
  • Ausdrucksstärkere Typsysteme (z. B. Typen mit eingeschränktem Bereich, benutzerdefinierte Typen wie Datensatztypen, starke Typisierung usw.)

C hat einige interessante Funktionen:

  • Rekursionsunterstützung (aufgrund der stapelbasierten automatischen Variablen im Vergleich zu Sprachen, in denen alle Variablen eine globale Lebensdauer haben)
  • Funktionszeiger
  • Benutzerdefinierte Datentypen (Strukturen und Gewerkschaften) wurden kurz nach der Erstveröffentlichung von C implementiert.
  • Die Zeichenfolgendarstellung von C (Pointer-to-Chars) ist eine enorme Verbesserung gegenüber B, bei dem mehrere Buchstaben in ein Maschinenwort codiert wurden.
  • Die Header-Dateien von C waren ein effizienter Hack, um die Kompilierungseinheiten klein zu halten, bieten aber auch ein einfaches Modulsystem.
  • Assembly-artige uneingeschränkte Zeiger und Zeigerarithmetik im Vergleich zu sichereren Referenzen. Zeiger sind eine von Natur aus unsichere Funktion, aber auch sehr nützlich für die Programmierung auf niedriger Ebene.

Zu der Zeit, als C entwickelt wurde, waren andere innovative Sprachen wie COBOL, Lisp, ALGOL (in verschiedenen Dialekten), PL / I, SNOBOL, Simula und Pascal bereits veröffentlicht und / oder für bestimmte Problembereiche weit verbreitet. Die meisten dieser vorhandenen Sprachen waren jedoch für die Programmierung von Großrechnern vorgesehen oder waren akademische Forschungsprojekte. ZB als ALGOL-60 zum ersten Mal als universelle Programmiersprache entwickelt wurde, existierte die notwendige Technologie und Informatik, um es zu implementieren, noch nicht. Einige davon (einige ALGOL-Dialekte, PL / I, Pascal) waren auch für die Programmierung auf niedriger Ebene gedacht, hatten jedoch tendenziell komplexere Compiler oder waren zu sicher (z. B. keine uneingeschränkten Zeiger). Pascal fehlt insbesondere eine gute Unterstützung für Arrays variabler Länge.

Im Vergleich zu diesen Sprachen lehnt C "elegante" und teure Funktionen ab, um für die Low-Level-Entwicklung praktischer zu sein. C war nie in erster Linie ein Forschungsprojekt für Sprachdesign. Stattdessen war es ein Ableger der Unix-Kernel-Entwicklung auf dem PDP-11-Minicomputer, der vergleichsweise ressourcenbeschränkt war. Für seine Nische (eine minimalistische Low-Level-Sprache zum Schreiben von Unix mit einem einfach zu portierenden Single-Pass-Compiler) ist C absolut herausragend - und über 45 Jahre später immer noch die Verkehrssprache der Systemprogrammierung.

amon
quelle
17
Nur eine kleine Ergänzung für Leute, die nicht wissen, was für die vorhandene ALGOL-Familie und Pascal-Sprachen notwendig ist: Diese Sprachen hatten lexikalisch verschachtelte Funktionen, mit denen Sie auf (lokale) Variablen zugreifen konnten, die in äußeren Funktionen deklariert wurden. Das bedeutete entweder, dass Sie bei jedem Funktionsaufruf und bei jedem Rücksprung (der die Lexikonebene änderte) eine "Anzeige" - eine Reihe von Zeigern auf äußere lexikalische Bereiche - pflegen mussten - oder dass Sie lexikalische Bereiche auf dem Stapel und jedem solchen variablen Zugriff verketten mussten benötigt mehrere indirekte Sprünge auf dem Stapel, um es zu finden. Teuer! C hat das alles abgeworfen. Ich vermisse es immer noch.
Davidbak
12
@davidbak: Die x86-64-System-V-ABI (auch als Aufrufkonvention unter Linux / OS X bezeichnet) ist %r10der "statische Kettenzeiger", von dem Sie genau sprechen. Für C ist es nur ein weiteres Rubbellos-Register, aber ich denke, Pascal würde es verwenden. (GNU C-verschachtelte Funktionen verwenden es, um einen Zeiger an den äußeren Gültigkeitsbereich zu übergeben, wenn eine solche Funktion nicht inline ist (z. B. wenn Sie einen Funktionszeiger darauf setzen, damit der Compiler ein Trampolin mit Maschinencode auf dem Stapel erstellt): Akzeptanz von regulär Verwendung von R10 und R11 )
Peter Cordes
2
@PeterCordes Faszinierend! Pascal war immer noch weit verbreitet, als System V herauskam (obwohl ich nicht weiß, wann das formale SysV-ABI definiert wurde). Ihre verknüpfte Antwort ist sehr informativ.
Davidbak
3
C hat benutzerdefinierte Typen (struct / union). Ich vermute, dass der Rest dieser "Features" weggelassen wurde, da sie keinen oder nur einen negativen Nutzen haben (es sei denn, Sie nehmen an einem verschleierten Codewettbewerb teil :-)), da sie das Ziel beeinträchtigen, die Sprache sowohl einfach als auch ausdrucksstark zu halten .
Jamesqf
6
@jamesqf: aber sehr früh hatte C keine Strukturzuweisung; Ich vermute, Sie müssen die Mitglieder einzeln kopieren, anstatt zu schreiben, a = b;um eine ganze Struktur so zu kopieren, wie Sie es in ISO C89 können. In frühen C-Versionen waren benutzerdefinierte Typen definitiv zweitklassig und konnten nur als Funktionsargumente als Referenz übergeben werden. Cs Abneigung gegen Arrays und auch Warum unterstützt C ++ die memberweise Zuweisung von Arrays innerhalb von Strukturen, aber nicht generell?
Peter Cordes
37

In den frühen 1970er Jahren war C mit modernen Konstrukten ein blendender Hauch frischer Luft, so dass das gesamte UNIX-System mit vernachlässigbarem Platz- oder Leistungsverlust aus der Assemblersprache in C umgeschrieben werden konnte. Viele Zeitgenossen bezeichneten es damals als Hochsprache.

Die Autoren von C, in erster Linie Dennis Ritchie, waren vorsichtiger und sagten im Artikel des Bell System Technical Journal: "C ist keine Hochsprache." Mit einem ironischen Lächeln und der Absicht, provokativ zu sein, würde Dennis Ritchie sagen, es sei eine Sprache mit niedrigem Sprachniveau. Zu seinen Konstruktionszielen für C gehörte es vor allem, die Sprache nahe an der Maschine zu halten und dennoch Portabilität zu gewährleisten, dh Maschinenunabhängigkeit.

Weitere Informationen finden Sie im Original-BSTJ-Artikel:

Danke Dennis. Mögest du in Frieden ruhen.

Knospe wonsiewicz
quelle
3
Es handelte sich im Grunde genommen um typisierte und schönere Syntax-Wrapper für die PDP-Assemblierung, wenn Sie mich fragen.
Einpoklum
2
@einpoklum Dem stimme ich eher zu. Ich habe C ungefähr 1980 an der Universität auf einer PDP-11 / 34a gelernt und es wurde von einem der Profis als "tragbare Assemblersprache" beschrieben. Wahrscheinlich, weil wir zusätzlich zum PDP-11 mehrere Superbrain CP / M-Maschinen im Labor hatten, auf denen ein C-Compiler verfügbar war. en.wikipedia.org/wiki/Intertec_Superbrain
dgnuff
2
Auch eine exzellente Antwort auf der Grundlage nachweisbarer historischer Beweise (wow! Es gab eine Vorversion des K & R!).
Christophe
7
@einpoklum Ist das nicht etwas weit hergeholt? Ich hatte die Möglichkeit, Mitte der 80er Jahre System- und Anwendungscode in Assembler (Z80 und M68K), einem "portablen Assembler" namens M (PDP11-Syntax mit abstraktem 16-Bit-Register und Befehlssatz) und C zu schreiben. Im Vergleich zu Assembler , C ist definitiv eine Hochsprache: Die Produktivität der C-Programmierung war um eine Größenordnung höher als in Assembler! Natürlich keine Zeichenketten (SNOBOL), keine native Unterstützung für Datendateien (COBOL), kein selbstgenerierender Code (LISP), keine fortgeschrittene Mathematik (APL), keine Objekte (SIMULA), daher können wir uns darauf einigen, dass es nicht sehr hoch war
Christophe
21

Wie ich an anderer Stelle auf dieser Site schrieb, als jemand das Muster der Verwaltung von malloc / freiem Speicher als "Low-Level-Programmierung" bezeichnete,

Komisch, wie sich die Definition von "Low-Level" im Laufe der Zeit ändert. Als ich das Programmieren zum ersten Mal lernte, wurde jede Sprache, die ein standardisiertes Heap-Modell bereitstellte, das ein einfaches Zuweisungs- / Freigabemuster ermöglicht, als hoch angesehen. Bei der Programmierung auf niedriger Ebene müssten Sie den Speicher selbst überwachen (nicht die Zuordnungen, sondern die Speicherorte selbst!) Oder Ihren eigenen Heap-Allokator schreiben, wenn Sie Lust dazu haben.

Im Kontext war dies in den frühen 90ern, lange nachdem C herauskam.

Mason Wheeler
quelle
War die Standardbibliothek nicht erst seit der Standardisierung Ende der 80er Jahre eine Sache (nun, basierend auf vorhandenen Unix-APIs)? Auch die Kernel-Programmierung (die ursprüngliche Problemdomäne von C) erfordert natürlich einfache Dinge wie die manuelle Speicherverwaltung. Zu der Zeit muss C die Programmiersprache der höchsten Ebene gewesen sein, in der ein seriöser Kernel geschrieben wurde (ich denke, heutzutage verwendet der NT-Kernel auch eine angemessene Menge an C ++).
amon
6
@hyde, ich habe Algol 60 verwendet, zwei verschiedene FORTRAN-Dialekte und mehrere verschiedene BASIC-Dialekte in den 1970er Jahren, und keine dieser Sprachen hatte Zeiger oder einen Heap-Allokator.
Solomon Slow
7
Genau genommen können Sie immer noch mit no programmieren, malloc()indem Sie den resultierenden Speicher direkt aufrufen brk(2)oder mmap(2)selbst verwalten. Es ist eine gewaltige PITA, für die es keinen vorstellbaren Nutzen gibt (es sei denn, Sie implementieren zufällig eine malloc-artige Sache), aber Sie können es tun.
Kevin
1
@amon - mit Ausnahme der bemerkenswerten Burroughs-Stack-basierten Maschinen, die von unten nach oben in ALGOL programmiert wurden ... und viel früher als Unix. Übrigens Multics, das war die Inspiration für Unix: Geschrieben in PL / I. Ähnlich wie ALGOL, höher als C.
Davidbak
6
Eigentlich hat der Grund, warum wir heute Multics nicht verwenden, wahrscheinlich mehr mit der Tatsache zu tun, dass es nur auf teuren Mainframes lief - dh den typischen unverschämten Mainframe-Kosten des Tages plus den Mehrkosten von einem halben Schrank Spezialisierte Hardware zur Implementierung von virtuellem Speicher mit Sicherheit. Als 32-Bit-Minicomputer wie der VAX-11 herauskamen, lösten sich alle außer den Banken und der Regierung von IBM und den Seven Dwarfs und verwandelten ihre groß angelegte Verarbeitung in "Mini" -Computer.
Davidbak
15

In vielen Antworten wurde bereits auf frühe Artikel verwiesen, in denen Dinge wie „C ist keine Hochsprache“ gesagt wurden.

Ich kann mich jedoch nicht dagegen wehren, viele, wenn nicht die meisten oder alle HLLs zu der Zeit - Algol, Algol-60, PL / 1, Pascal - haben die Überprüfung der Array-Grenzen und die Erkennung von numerischen Überläufen bereitgestellt.

Das letzte Mal habe ich überprüft, ob Puffer- und Ganzzahlüberläufe die Hauptursache für viele Sicherheitslücken sind. ... Ja, immer noch der Fall ...

Die Situation für die dynamische Speicherverwaltung war komplizierter, dennoch war C-style malloc / free ein großer Sicherheitsrückschritt.

Wenn Ihre Definition von HLL also "viele Bugs auf niedriger Ebene automatisch verhindert" enthält, wäre der traurige Zustand der Cybersicherheit sehr unterschiedlich, wahrscheinlich besser, wenn C und UNIX nicht vorgekommen wären.

Krazy Glew
quelle
7
Da ich zufällig an der Implementierung von Intel MPX und dem Pointer / Bounds-Checking-Compiler beteiligt war, der herausgekommen ist, kann ich Sie auf die Artikel über deren Leistung verweisen: im Wesentlichen 5-15%. Ein Großteil davon sind Compiler-Analysen, die in den 1970er und 1980er Jahren kaum möglich waren - im Vergleich zu naiven Überprüfungen, die um 50% langsamer sein könnten. Ich denke jedoch, dass es gerechtfertigt ist zu sagen, dass C und UNIX die Arbeit an solchen Analysen um 20 Jahre zurückgesetzt haben - als C die beliebteste Programmiersprache wurde, gab es viel weniger Nachfrage nach Sicherheit.
Krazy Glew
9
@jamesqf Außerdem hatten viele Computer vor C spezielle Hardware-Unterstützung für die Überprüfung von Grenzen und Ganzzahlüberläufen. Da C diese HW nicht verwendete, wurde sie schließlich verworfen und entfernt.
Krazy Glew
5
@jamesqf Zum Beispiel: Die MIPS RISC ISA basierte ursprünglich auf den Stanford-Benchmarks, die ursprünglich in Pascal geschrieben wurden, und wurde später nach C verschoben. Da Pascal in Befehlen wie ADD nach einem vorzeichenbehafteten Integer-Überlauf suchte, tat dies auch MIPS. Etwa 2010 arbeitete ich bei MIPS, mein Chef wollte nicht verwendete Anweisungen in MIPSr6 ​​entfernen, und Studien zeigten, dass die Überlaufprüfungen so gut wie nie verwendet wurden. Es stellte sich jedoch heraus, dass Javascript solche Überprüfungen durchführte - aber die billigen Anweisungen wegen mangelnder Betriebssystemunterstützung nicht verwenden konnte.
Krazy Glew
3
@KrazyGlew - Es ist sehr interessant, dass Sie dies ansprechen, da in C / C ++ der Kampf zwischen Benutzern und Compiler-Autoren um "undefiniertes Verhalten" aufgrund eines vorzeichenbehafteten Integer-Überlaufs zunimmt, da Compiler-Autoren heutzutage das alte Mantra "Making a wrong" verwendet haben Programm schlechter ist keine Sünde "und drehte es auf 11. Viele Beiträge auf Stackoverflow und anderswo spiegeln dies ...
Davidbak
2
Wenn Rust über SIMD-Eigenheiten wie C verfügt, könnte dies eine nahezu ideale, moderne, tragbare Assemblersprache sein. C wird als portable Assemblersprache immer schlechter, da die UB-basierte Optimierung aggressiv ist und neue primitive Operationen, die moderne CPUs unterstützen (wie popcnt, count leading / trailing zeros, bit-reverse, byte-reverse, saturating), nicht portabel verfügbar gemacht werden können Mathematik). Um C-Compiler auf CPUs mit HW-Unterstützung effizienter für diese zu machen, sind häufig nicht tragbare Eigenheiten erforderlich. Wenn der Compiler Popcnt auf Zielen emuliert, ohne dass es besser ist, als die Spracherkennung zu erhalten popcnt.
Peter Cordes
8

Betrachten Sie ältere und viel höhere Sprachen vor C (1972):

Fortran - 1957 (nicht viel höher als C)

Lisp - 1958

Cobol - 1959

Fortran IV - 1961 (nicht viel höher als C)

PL / 1 - 1964

APL - 1966

Plus eine Mittelstufensprache wie RPG (1959), meistens eine Programmiersprache, um auf Plugboards basierende Einheitsaufzeichnungssysteme zu ersetzen.

Aus dieser Perspektive schien C eine sehr niedrige Sprache zu sein, nur ein wenig über den Makroassemblern, die zu dieser Zeit auf Großrechnern verwendet wurden. Bei IBM-Mainframes wurden Assembler-Makros für den Datenbankzugriff verwendet, z. B. BDAM (Basic Disk Access Method), da die Datenbankschnittstellen (zu diesem Zeitpunkt) nicht nach Cobol portiert worden waren, was zu einer Vermischung von Assembly und führte Cobol-Programme, die noch heute auf IBM-Mainframes verwendet werden.

rcgldr
quelle
2
Wenn Sie ältere, höhere Sprachen auflisten möchten, vergessen Sie LISP nicht .
Deduplizierer
@ Deduplicator - Ich habe es der Liste hinzugefügt. Ich habe mich auf das konzentriert, was auf IBM-Mainframes verwendet wurde, und ich erinnere mich nicht, dass LISP so beliebt war, aber APL war auch eine Nischensprache für IBM-Mainframes (über Time-Sharing-Konsolen) und IBM 1130. Ähnlich wie LISP ist APL eine von Die einzigartigeren Hochsprachen zeigen beispielsweise, wie wenig Code erforderlich ist, um Conways Spiel des Lebens mit einer aktuellen Version von APL zu erstellen: youtube.com/watch?v=a9xAKttWgP4 .
rcgldr
2
Ich würde RPG oder COBOL nicht als besonders hoch eingestuft, zumindest nicht vor COBOL-85. Wenn Sie die Oberfläche von COBOL zerkratzen, sehen Sie, dass es sich im Wesentlichen um eine Sammlung sehr fortschrittlicher Assembler-Makros handelt. Zunächst fehlen ihm sowohl Funktionen, Prozeduren und Rekursionen als auch jegliche Art von Scoping. Jeder Speicher muss oben im Programm deklariert werden, was entweder zu extrem langen Ouvertüren oder zu einer schmerzhaften Wiederverwendung von Variablen führt.
Idrougge
Ich habe einige schlechte Erinnerungen an die Verwendung von Fortran IV. Ich erinnere mich nicht, dass es merklich "höher" als C war.
DaveG
@idrougge - COBOL und RPG sowie Mainframe-Anweisungssätze umfassten die vollständige Unterstützung für gepacktes oder entpacktes BCD, eine Voraussetzung für Finanzsoftware in Ländern wie den USA. Ich betrachte die verwandten nativen Operatoren wie "entsprechend verschieben" als hoch. RPG war insofern ungewöhnlich, als Sie die Verknüpfung zwischen unformatierten Eingabefeldern und formatierten Ausgabefeldern und / oder Akkumulatoren angegeben haben, jedoch nicht die Reihenfolge der Operationen, ähnlich wie bei der von ihm ersetzten Plugboard-Programmierung.
RCGLDR
6

Die Antwort auf Ihre Frage hängt davon ab, um welche C-Sprache es sich handelt.

Die Sprache, die in Dennis Ritchies C-Referenzhandbuch von 1974 beschrieben wurde, war eine einfache Sprache, die den Programmierkomfort höherer Programmiersprachen bot. Von dieser Sprache abgeleitete Dialekte waren ebenfalls eher einfache Programmiersprachen.

Als der C-Standard 1989/1990 veröffentlicht wurde, beschrieb er jedoch nicht die für die Programmierung tatsächlicher Maschinen populäre Low-Level-Sprache, sondern eine höhere Sprache, die sein könnte - aber nicht sein musste. -implementiert in untergeordneten Begriffen.

Wie die Autoren des C-Standards bemerken, war eines der Dinge, die die Sprache nützlich machten, dass viele Implementierungen als Assembler auf hoher Ebene behandelt werden konnten. Da C auch als Alternative zu anderen Hochsprachen verwendet wurde und viele Anwendungen nicht die Fähigkeit erforderten, Dinge zu tun, die Hochsprachen nicht konnten, erlaubten die Autoren des Standards, dass sich Implementierungen willkürlich verhalten wenn Programme versuchten, Konstrukte auf niedriger Ebene zu verwenden. Folglich war die von der C-Norm beschriebene Sprache niemals eine Programmiersprache auf niedriger Ebene.

Überlegen Sie, wie Ritchies Sprache und C89 das Codefragment anzeigen, um diese Unterscheidung zu verstehen:

struct foo { int x,y; float z; } *p;
...
p[3].y+=1;

Auf einer Plattform, auf der "char" 8 Bit, "int" 16 Bit Big-Endian, "float" 32 Bit und Strukturen ohne spezielle Auffüll- oder Ausrichtungsanforderungen sind, beträgt die Größe von "struct foo" 8 Byte.

In Ritchies Sprache würde das Verhalten der letzten Anweisung die in "p" gespeicherte Adresse annehmen, 3 * 8 + 2 [dh 26] Bytes hinzufügen und einen 16-Bit-Wert aus den Bytes an dieser und der nächsten Adresse abrufen Fügen Sie diesem Wert einen hinzu, und schreiben Sie diesen 16-Bit-Wert in dieselben zwei Bytes zurück. Das Verhalten würde so definiert, dass es auf das 26. und 27. Byte folgt, das auf das unter der Adresse p angegebene folgt, ohne Rücksicht darauf, welche Art von Objekt dort gespeichert ist.

In der durch den C-Standard definierten Sprache würde für den Fall, dass * p ein Element eines "struct foo []" identifiziert, auf das mindestens drei vollständigere Elemente dieses Typs folgen, die letzte Anweisung dem Mitglied y von eins hinzufügen das dritte Element nach * p. Unter keinen anderen Umständen würde das Verhalten durch den Standard definiert.

Ritchies Sprache war eine einfache Programmiersprache, da sie es einem Programmierer ermöglichte, Abstraktionen wie Arrays und Strukturen zu verwenden, wenn dies zweckmäßig war, und das Verhalten in Bezug auf das zugrunde liegende Layout von Objekten im Speicher definierte. Im Gegensatz dazu definiert die von C89 und späteren Standards beschriebene Sprache die Dinge im Sinne einer übergeordneten Abstraktion und definiert nur das Verhalten von Code, das damit übereinstimmt. Qualitativ hochwertige Implementierungen, die für die Programmierung auf niedriger Ebene geeignet sind, verhalten sich in mehr Fällen als im Standard vorgeschrieben, aber es gibt kein "offizielles" Dokument, in dem angegeben ist, was eine Implementierung tun muss, um für solche Zwecke geeignet zu sein.

Die von Dennis Ritchie erfundene C-Sprache ist daher eine einfache Sprache und wurde als solche anerkannt. Die vom C-Normungsausschuss erfundene Sprache war jedoch nie eine Sprache mit niedrigem Sprachniveau, da keine Garantien für die Implementierung vorlagen, die über die Vorgaben des Standards hinausgingen.

Superkatze
quelle