JavaRush /Java-Blog /Random-DE /Ebenen von Programmiersprachen
Marat Sadykov
Level 41

Ebenen von Programmiersprachen

Veröffentlicht in der Gruppe Random-DE

Einführung

Welche verschiedenen Programmiersprachen gibt es? Welche Konzepte sind darin verankert? Wie haben sie sich entwickelt? In diesem Artikel betrachten wir die Arten von Programmiersprachen basierend auf den sogenannten Ebenen – von Maschinencodes (niedriges Niveau, nah an Computerhardware) bis hin zu Sprachen wie Java oder C# (hohes Niveau). Je weniger Transformationen die Textauflistung des Programms auf dem Weg zur Umwandlung in eine Menge von Nullen und Einsen durchläuft, desto niedriger ist die Ebene.
Stufen der Programmiersprachen – 1
Als nächstes schauen wir uns Folgendes an:
  1. Low-Level-Sprachen (Maschinencodes und Assembler)
  2. Mittelstufe (C, Fortran….)
  3. Hohes Niveau (C++, Java, Python, Ruby, JavaScript...)
Der Level charakterisiert auch, wie detailliert die Auflistung des zukünftigen Programms sein muss, um die Umsetzung umzusetzen. Wie einfach ist dieser Prozess für den Menschen? Das Niveau einer Sprache sollte nicht als eindeutiger Indikator für ihre Fähigkeiten angesehen werden. Eine Programmiersprache ist ein Werkzeug, das in einem Bereich effektiv und in anderen weniger nützlich ist. Sowohl der Tischler als auch der Tischler arbeiten mit Holz. Das erste hat ein Hauptwerkzeug – einen Satz Meißel, das zweite – eine Axt. Allerdings wird ein Tischler einen geschnitzten Schrank eleganter machen und ein Haus schneller bauen. Obwohl jeder in der Lage ist, die Arbeit des anderen zu erledigen, werden sie diese viel weniger effizient erledigen. Verschiedene Daten in einem Computer werden als Mengen von Nullen und Einsen dargestellt. Steuerbefehle für seine Verarbeitung sind dieselben Daten, die Anweisungen enthalten, die den Speicherort der erforderlichen Informationen und die Art der Änderung bestimmen.

Maschinensprachen (unterstes Niveau)

Wir müssen einen kurzen Besuch vom Software-Bereich zum Hardware-Bereich machen. Betrachten wir es in vereinfachter Form. Der Prozessor ist das wichtigste „Gehirn“ des Computers. Das Motherboard, auf dem es installiert ist, enthält Controller, die über Busse (Datenkanäle für die Kommunikation) mit anderen Geräten interagieren.
Stufen der Programmiersprachen – 2
Einige arbeiten mit hoher Geschwindigkeit (rote Pfeile): Der Prozessor bezieht Befehle aus dem Speicher und manipuliert Daten, die Grafikkarte verbraucht, insbesondere in 3D-Spielen, riesige Mengen an Texturen, Formen, Pixelkoordinaten und anderen Objekten, um ein Bild auf dem Monitorbildschirm aufzubauen . Andere benötigen (aufgrund der begrenzten Geschwindigkeit des Informationsaustauschs) keine so hohen Indikatoren. Verschiedene interne und externe Geräte sind im Diagramm mit grünen Pfeilen verbunden.

Die innere Welt des Prozessors

Alle Prozessorbefehle kommen aus dem Speicher und werden in binärer Form ausgeführt. Das Format, die Anzahl und die Teilmenge der Anweisungen hängen von seiner Architektur ab. Die meisten von ihnen sind untereinander unvereinbar und verfolgen unterschiedliche Ideologien. Und auch die Art des Befehls hängt stark vom Modus (8/16/32... Bittiefe) und der Datenquelle (Speicher, Register, Stack...) ab, mit der der Prozessor arbeitet. Die gleiche Aktion kann durch unterschiedliche Anweisungen dargestellt werden. Der Prozessor verfügt über Anweisungen zum Hinzufügen zweier Operanden (ADD X,Y) und zum Hinzufügen eines Operanden zum angegebenen Operanden (INC X). Das Hinzufügen eines Tripels zu einem Operanden kann als ADD X,3 oder durch dreimaliges Aufrufen von INC X erfolgen. Und für verschiedene Prozessoren ist es unmöglich vorherzusagen, welche dieser Methoden hinsichtlich Geschwindigkeit oder Speicherbedarf optimal ist. Der Einfachheit halber werden binäre Informationen in hexadezimaler Form geschrieben. Betrachten wir einen Teil eines bekannten Programms (C-Sprache, deren Syntax der von Java ähnelt).
int func() {
    int i = getData("7") ;
    return ++i;
   ...
}
Code, der die gleichen Aktionen in Form einer Befehlsfolge für den Prozessor umsetzt: ... 48 83 ec 08 bf bc 05 20 00 31 c0 e8 e8 fe ff ff 48 83 c4 08 83 c0 01 ... So sieht die Low-Level-Programmiersprache für den Intel-Prozessor tatsächlich aus. Ein Fragment, das eine Methode mit einem Argument aufruft und das um eins erhöhte Ergebnis zurückgibt. Dabei handelt es sich um Maschinensprache (Code), die direkt, ohne Transformationen, zur Ausführung an den Prozessor übertragen wird. Vorteile:
  • Wir beherrschen die Situation vollkommen und verfügen über die umfassendsten Einsatzmöglichkeiten des Prozessors und der Computerhardware.
  • Uns stehen alle Möglichkeiten zur Organisation und Optimierung von Code zur Verfügung.
Nachteile:
  • Es ist notwendig, über umfassende Kenntnisse über die Funktionsweise von Prozessoren zu verfügen und bei der Codeausführung eine Vielzahl von Hardwarefaktoren zu berücksichtigen.
  • Das Erstellen von Programmen, die etwas komplexer sind als das angegebene Beispiel, führt zu einem starken Anstieg des Zeitaufwands für das Schreiben und Debuggen von Code.
  • Plattformabhängigkeit: Ein Programm, das für einen Prozessor erstellt wurde, funktioniert im Allgemeinen nicht auf anderen. Es ist möglich, dass für diesen Prozessor in anderen Betriebsmodi eine Codebearbeitung erforderlich ist.
Maschinencodes waren zu Beginn der Computer weit verbreitet; andere Programmiermethoden gab es im Zeitalter der Computerpioniere nicht. Derzeit werden sie gelegentlich von Mikroelektronik-Ingenieuren bei der Entwicklung oder beim Testen von Prozessoren auf niedriger Ebene verwendet.

Assemblersprache (niedriges Niveau)

Im Gegensatz zu einem Computer nehmen Sie und ich Informationen besser in Text-/semantischer Form wahr als in digitaler Form. Fünfzig Kontaktnamen können Sie problemlos auf Ihrem Smartphone benennen, die dazugehörigen Telefonnummern werden Sie aber wahrscheinlich nicht auswendig schreiben können. Beim Programmieren ist es genauso. Wir steigen auf der Typenleiter auf, indem wir drei grundlegende Schritte unternehmen:
  • Ordnen wir eine symbolische Anweisung Gruppen digitaler Prozessoranweisungen zu, die entsprechende Aktionen ausführen.
  • Lassen Sie uns die Argumente der Prozessoranweisungen separat hervorheben.
  • Lassen Sie uns die Möglichkeit einführen, Speicherbereiche, Variablen und den Speicherort einzelner Befehle zu benennen.
Vergleichen wir Fragmente des vorherigen Programms im Maschinencode (Mitte) und in Assemblersprache (rechts):
2004b0     48 83 ec 08      sub    $0x8,%rsp
2004b4     bf bc 05 20 00   mov    $0x2005bc,%edi
2004b9     31 c0            xor    %eax,%eax
2004bb     e8 e8 fe ff ff   callq  getData
2004c0     48 83 c4 08      add    $0x8,%rsp
2004c4     83 c0 01         add    $0x1,%eax
Wie Sie sehen, wurde der Prozess des Schreibens eines Programms vereinfacht: Es besteht keine Notwendigkeit, Nachschlagewerke zum Generieren digitaler Befehlswerte, zum Berechnen von Übergangslängen, zum Verteilen von Daten im Speicher auf seine Zellen und für andere Prozessorfunktionen zu verwenden. Wir beschreiben die erforderliche Aktion anhand einer Reihe symbolischer Befehle und der für die Ausführungslogik erforderlichen Argumente. Anschließend übersetzt das Übersetzerprogramm die Textdatei in eine Reihe von Nullen und Einsen, die für den Prozessor verständlich sind. Vorteile:
  • Der Prozess des Schreibens und Änderns von Code wurde vereinfacht.
  • Die Kontrolle über alle Hardwareressourcen blieb erhalten.
  • Es ist relativ einfacher, das Programm auf andere Plattformen zu portieren, diese erfordern jedoch je nach Hardwarekompatibilität Modifikationen.
Nachteile:
  • Die Assemblersprache ist eine Low-Level-Programmiersprache. Es ist schwierig, selbst kleine Codeabschnitte zu erstellen. Darüber hinaus muss auch der spezifische Betrieb der Anlage berücksichtigt werden.
  • Plattformabhängigkeit.
Das beliebteste Java-Demo-Beispiel:
public static void main(String[] args) {
    System.out.println("Hello World!");
}
wird wie folgt aussehen (NASM-Syntax, unter Verwendung der Windows-API und kernel32.lib):
global _main
	extern  _GetStdHandle@4
	extern  _WriteFile@20
	extern  _ExitProcess@4

	section .text
_main:
	; DWORD  bytes;
	mov 	ebp, esp
	sub 	esp, 4

	; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
	push	-11
	call	_GetStdHandle@4
	mov 	ebx, eax

	; WriteFile( hstdOut, message, length(message), &bytes, 0);
    push	0
	lea 	eax, [ebp-4]
	push	eax
	push	(message_end - message)
	push	message
	push	ebx
	call	_WriteFile@20

	; ExitProcess(0)
	push	0
	call	_ExitProcess@4

	; never here
	hlt
message:
	db  	'Hello, World', 10
message_end:
Wie Maschinencodes wird auch die Assemblersprache häufiger von Ingenieuren und Systemprogrammierern verwendet. Es wird verwendet, um hardwareabhängige Teile des Betriebssystemkerns zu schreiben, die zeitkritisch oder für die Implementierungsfunktionen von Treibern für verschiedene Peripheriegeräte von entscheidender Bedeutung sind. Doch in letzter Zeit greifen sie immer seltener darauf zurück, da seine Nutzung die Portabilität von Programmen auf andere Plattformen stark einschränkt. Manchmal verwenden sie den Disassembly-Prozess – sie erstellen eine Assembly-Liste eines Programms aus digitalen Codes, um die Logik der Ausführung kleiner Fragmente zu analysieren. In seltenen Fällen, wenn der ursprüngliche High-Level-Code nicht verfügbar ist: Analyse von Viren zu deren Bekämpfung oder Verlust des Quellcodes. Die Assemblersprache gilt als die erste/zweite Generation (wir werden die Pseudocodes vor dem Aufkommen des Assemblers und ihren Unterschied zu symbolischen Befehlen nicht gesondert betrachten). Ich möchte die Verwendung von Assembler in Demo Scene hervorheben: eine Verschmelzung von Kunst, Mathematik und Low-Level-Codierung, die die künstlerischen Ideen ihrer Schöpfer in Form von Programmen verkörpert, die Videoclips mit begrenzten Ressourcen generieren. Oftmals sollte die Gesamtgröße von Programm und Datendatei 256 Byte nicht überschreiten (beliebt ist auch das 4/64-Kilobyte-Format). Hier ist ein Beispiel für ein 4-KB-Programm:

Gruppe C/Fortran-Sprachen (mittleres/hohes Niveau)

Mit der Entwicklung der Fähigkeiten der Computertechnologie waren der Umfang der Funktionalität und der Zeitpunkt der Codeimplementierung in Assembler nicht mehr zufriedenstellend. Die Kosten für das Schreiben, Testen und Warten von Programmen stiegen um eine Größenordnung schneller als ihre Möglichkeiten. Es war notwendig, die Anforderungen an den Programmierer hinsichtlich der Kenntnisse über die Funktionsweise der Geräte zu reduzieren, um ihm ein Werkzeug an die Hand zu geben, das es ihm ermöglichen würde, in Sprachen zu schreiben, die der menschlichen Logik nahe kommen. Wechseln Sie zu einer neuen Ebene der Programmiersprachentypen. Bereitstellung der Möglichkeit zur Aufteilung in verschiedene Module mit weiterem sequentiellem Aufruf (prozedurales Programmierparadigma), Bereitstellung verschiedener Datentypen mit der Möglichkeit, diese zu konstruieren usw. Darüber hinaus führten diese Maßnahmen zu einer verbesserten Portabilität des Codes auf andere Plattformen und einer komfortableren Organisation Zusammenarbeit. Eine der ersten Sprachen, die all das unterstützte, war Fortran, das in den 50er Jahren des letzten Jahrhunderts entwickelt wurde . Die Fähigkeit, in Textform eine Beschreibung der Ausführungslogik zu erstellen, indem Schleifen, Verzweigungen, Unterroutinen verwendet werden, mit Arrays gearbeitet wird und Daten in Form reeller, ganzer und komplexer Zahlen dargestellt werden, begeisterte Ingenieure und Wissenschaftler. In kurzer Zeit entstanden wissenschaftliche „Rahmenwerke“ und Bibliotheken. All dies war eine Folge der Tatsache, dass Fortran auch heute noch relevant ist, wenn auch in einem engen wissenschaftlichen Umfeld, und sich weiterentwickelt, da das Gepäck an Entwicklungen sehr groß ist, allein die IMSL- Bibliothek entwickelt sich seit 1970 (!) aktiv weiter, wie Können Sie sich an viele ähnlich relevante Software erinnern? -Oldtimer? Ein weiterer Zweig der Sprachentwicklung auf dieser Ebene ist C. Wenn Fortran zu einem Werkzeug für Wissenschaftler wurde, dann wurde C entwickelt, um Programmierern bei der Erstellung von Anwendungssoftware zu helfen: Betriebssysteme, Treiber usw. Die Sprache ermöglicht die manuelle Steuerung der Speicherzuweisung und ermöglicht den direkten Zugriff auf Hardwareressourcen. C-Programmierer müssen Low-Level-Entitäten steuern, daher sind viele der Meinung, dass C eine fortgeschrittene Assemblersprache ist und oft als „Mid-Level“-Sprache bezeichnet wird. Durch die Einführung der Datentypisierung in Assembler, Elemente der prozeduralen und modularen Programmierung ist die C-Sprache immer noch eine der Hauptsprachen für die Systemprogrammierung, was auch durch die rasante Entwicklung der Mikroelektronik in jüngster Zeit erleichtert wird. Alle Arten von Gadgets, Controllern, Netzwerken und anderen Geräten benötigen Treiber, die Implementierung von Protokollen für die Zusammenarbeit und andere relativ einfache Software, um die Interaktion mit den Geräten zu implementieren. All dies trägt zur heutigen Nachfrage nach der Sprache bei. Objektorientierte und funktionale Prinzipien wurden in Form von C++, C#, Java weiterentwickelt und dabei viel von der C-Syntax übernommen. Vorteile:
  • Vereinfachung des Code-Erstellungsprozesses: Einführung von Typen, Aufteilung in Module, Reduzierung von Programmlisten.
  • Прозрачная логика заложенного алгоритма вследствие ухода от машинных Codeов к более понятным для человека командам в семантически описательном стиле.
  • Переносимость. Стало достаточно перекомпoderровать текст программы для выполнения на другой платформе (возможно, с небольшой модификацией).
  • Скорость откомпoderрованных программ.
Минусы:
  • Отсутствие автоматического управления памятью и необходимость постоянного её контроля.
  • Отсутствие реализации концепций ein Objektно-ориентированного и функционального программирования.

Развитие языков высокого уровня

Hochentwickelte Programmiersprachen haben sich im Hinblick auf die Softwareerstellung zunehmend von Maschinencodes entfernt und implementieren neben prozeduralen auch verschiedene Programmierparadigmen. Dazu gehört auch die Umsetzung objektorientierter Prinzipien. C++, Java, Python, JavaScript, Ruby... – das Spektrum an Sprachen dieser Art ist heute am beliebtesten und gefragtesten. Sie bieten mehr Möglichkeiten zur Implementierung unterschiedlicher Software und es ist unmöglich, die „Spezialisierung“ jeder einzelnen Software eindeutig zu bestimmen. Aber die Popularität der Anwendung in relevanten Bereichen ist auf Bibliotheken/Frameworks für die Arbeit mit ihnen zurückzuführen, zum Beispiel: JavaScript – Frontend. Die Sprache wurde für die Interaktion zwischen einem Client-Webbrowser und einem Benutzer und einem Remote-Server entwickelt. Die beliebtesten Bibliotheken sind Angular, React und VUE. Derzeit wird es relativ aktiv auf Web- und anderen Servern (Backend) verwendet, Node.js ist besonders beliebt. Ruby – Backend. Es wird zum Erstellen von Skripten (Dienstdateien) und auf Webservern verwendet. Das Hauptframework ist Ruby On Rails. Python ist eine wissenschaftliche und technische Domäne (neben der Webdomäne). Es ist eine Alternative zu Standard-Computer- und Mathematikpaketen (Mathematica, Octave, MatLab...), verfügt aber über die übliche Semantik der Sprache und eine große Anzahl von Bibliotheken. Hat viele Fans im Bereich maschineller Lernsysteme, Statistik und künstliche Intelligenz. Zu den häufig verwendeten Bibliotheken gehören Django, Numpy, Pandas und Tensorflow. C++ – Universelle, evolutionäre Weiterentwicklung der C-Sprache. Bietet funktionale und objektorientierte Programmierfunktionen, ohne die Fähigkeit zur Interaktion mit Low-Level-Hardware zu verlieren. Dadurch werden Produktivität und Flexibilität bei der Softwareerstellung realisiert, aber auch der Preis entspricht: eine hohe Eintrittsbarriere aufgrund der komplexen Spezifikation der Sprache, die Notwendigkeit einer unabhängigen Kontrolle über die Ressourcen bei der Ausführung des Programms. Viele Einzelbenutzer- und Systemsoftware wird damit geschrieben: Betriebssystemmodule (Windows, Symbian...), Spiele, Editoren (Adobe Photoshop, Autodesk Maya...), Datenbanken (MSSQL, Oracle...), Player ( WinAmp...) usw. Es ist zu beachten, dass moderne Software ein komplexes Produkt ist, bei dessen Entwicklung mehrere Programmiersprachen gleichzeitig verwendet werden und es sehr schwierig sein kann, den Grad der Beteiligung jeder einzelnen davon zu bestimmen das Gesamtergebnis.

Weiteren Fortschritt

In letzter Zeit erfreut sich eine andere Art der Programmierung zunehmender Beliebtheit – die funktionale (Weiterentwicklung des Sprachniveaus) . Hier ist eine andere Art der Abstraktion für Berechnungen – Funktionen, die eine Reihe von Funktionen als Argumente verwenden und eine andere zurückgeben. Die Rolle von Variablen übernehmen die gleichen Funktionen (Variablen, die wir kennen, sind einfach konstante Ausdrücke, ähnlich wie final vor einer Typdeklaration in Java). Die Funktion selbst ist in ihrem Gültigkeitsbereich geschlossen, das Ergebnis ihrer Operation hängt nur von den übergebenen Argumenten ab. Daraus ergeben sich zwei bemerkenswerte Eigenschaften:
  • Zum Testen benötigen wir nur Funktionsargumente (das Ergebnis der Arbeit hängt nicht von externen Variablen usw. ab).
  • Ein Programm im funktionalen Stil ist auf wundersame Weise für Parallelität geeignet: Sequentielle Funktionsaufrufe können in benachbarten Threads ausgegeben werden (da sie nicht von externen Faktoren beeinflusst werden) und erfordern keine Sperren (d. h. es gibt keine Synchronisierungsprobleme). Angesichts der weit verbreiteten Verbreitung von Multicore-Prozessoren ist dies ein guter Anreiz, sich diesem Thema zu widmen.
Allerdings ist die Eintrittsschwelle höher als bei OOP: Für effektiven Code ist es notwendig, ein Programm zu erstellen, das den Ausführungsalgorithmus in Form von Funktionen beschreibt. Aber auch für einen rein funktionalen Stil wäre es schön, die Grundlagen der Logik und Kategorientheorie zu kennen. Am beliebtesten sind Haskell, Scala, F#. Aber keine Angst, Elemente der funktionalen Programmierung sind in Java (wie auch in anderen modernen Sprachen der dritten Generation) aufgetaucht und können mit OOP kombiniert werden. All diese Details lernst du beim JavaRush Online-Praktikum genauer kennen. Das Gebiet der Logikprogrammierung (die nächste Ebene der Sprachen) hat aufgrund der geringen Nachfrage noch keine breite praktische Anwendung gefunden. Für die Erstellung von Programmen sind Kenntnisse der Grundlagen der diskreten Mathematik, der Prädikatenlogik, der Constraint-Tools und anderer Zweige der mathematischen Logik erforderlich. Die beliebteste aktive Sprache ist Prolog.

Abschluss

Derzeit sind OOP die am häufigsten verwendeten Sprachen. Java war seit seiner Einführung immer an der Spitze, normalerweise unter den ersten drei, der beliebtesten Sprachen. Zusätzlich zu OOP enthält es Elemente der funktionalen Programmierung, und Sie können verschiedene Schreibstile für Ihre Programme kombinieren. Das Anwendungsspektrum von Java ist sehr breit – das sind Geschäftsaufgaben, die Implementierung von Webservern (Backend), die Hauptsprache zur Erstellung von Android-Anwendungen, plattformübergreifende Programmierumgebungen und -arbeitsplätze (IDE/AWM) und Modellierung und vieles mehr . Besonders stark ist Java im Enterprise-Bereich – einem Bereich der Unternehmenssoftware, der hochwertigen und langlebigen Code und die Implementierung komplexester Geschäftslogiken erfordert.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION