Die Community zu .NET und Classic VB.
Menü

Programmiersprachen - der ewige Streit

 von 

Übersicht 

Da die Frage VB contra C im Forum immer wieder die Gemüter bewegt, ist dieser Artikel endlich einmal ein wohltuend praktischer Beitrag zu diesem Thema.

Mit freundlichen Grüßen
Jan Krumsiek

Einleitung  

Sie kennen das sicherlich auch: Unter Programmierern (oder denen, die sich dafür halten) gibt es immer wieder das leidige Streit-Thema, welche Programmiersprache "Die Beste" sei. In diesem Artikel möchte ich meine Vorstellungen und Konzepte zu diesem Thema darlegen.

Im Angebot der Programmiersprachen liegen meistens

  • Visual Basic on Microsoft
  • Delphi von Borland
  • C++ in irgendeiner Variante (meist Visual C++ von Microsoft)
  • Für die Veteranen und Geschwindigkeits-Freaks reine Assembler-Programme, wobei das Schreiben eines komplexen Windows-Programmes in Assembler als nicht sehr ernst zunehmende Aufgabe betrachtet werden kann.

Die Streits darüber sind teilweise wirklich endlos. Die eine Seite sagt, Visual Basic z.B. sei keine "Kinder-Programmiersprache" mehr wie früher und sei durchaus zu höherem fähig, die andere Seite sagt, um C++ kommt nichts herum und man benötige die Geschwindigkeit des Codes und die Fähigkeiten der Sprache unbedingt.

Ein anderer Aspekt ist sicherlich auch der schulische Wert. Mit welcher Programmiersprache kann man das "Programmieren" am besten lernen? Auch zu dieser Frage werde ich in diesem Artikel Stellung nehmen.

Professionelles Programmieren  

Gleich vorneweg: Ich selbst bezeichne mich nicht als "professioneller Programmierer", ich selbst schreibe ja auch nur Shareware-Anwendungen. Ich versuche hier vielmehr, meine eigenen Erfahrungen und Eindrücke einzubringen. Das heisst also meine Meinung, was man fürs Professionelle Programmieren benötigt.

Meine Lösung dieser Streitfrage liegt in einer Art Kompromiss zwischen den Programmiersprachen. Heutzutage gibt es doch für wirklich alles Schnittstellen und Wege der Kommunikation. Warum also soll man sich auf eine Programmiersprache beschränken, wenn man eventuell mit mehreren auf einmal viel mehr erreichen könnte.

Die einfachen Programmiersprachen, für alles, was damit möglich ist, und die komplexeren für die geschwindigkeits-bedürftigen Funktionen (die sog. "Flaschenhälse" des Programmes).

Noch eine Frage der Definition: Für mich (es mag andere Meinungen geben) sind in diesem Artikel "Microsoft Visual Basic" und "Borland Delphi" dieselbe Art von Entwicklungsprogramm; warum erkläre ich später, jedenfalls werde ich hier immer Visual Basic verwenden.

Visual Basic  

1. GUI (Grafische Benutzeroberfläche)

Die GUI (= Graphical User Interface = Grafische Benutzeroberfläche) ist der Teil eines Programmes, mit dem der Endbenutzer interagiert, sprich die Fenster, Buttons, Textboxen, Listen, Menüs etc.

Egal, was alles gegen Visual Basic gesagt wird, es kann niemand bestreiten, dass es keine einfachere Möglichkeit, eine GUI zu konstruieren, als Visual Basic! Per einfachstem DragnDrop können die Controls auf einem Fenster platziert werden.

Nun werden sicher einige Leute sagen, "Aber in Visual C++ gibt es doch auch einen Dialog-Editor. Der kann dasselbe wie Visual Basic!". Sicherlich ist das optische Design genauso leicht, aber in Visual C++ kann man z.B. nicht einfach einen Button doppelklicken und direkt den Code für seine Funktionsweise editieren. Außerdem ist die "automatische" Objektorientierung aller Controls einfach herrlich für die einfache Manipulation von Controls und die Interaktion zwischen allen Controls.

2. Überprüfen von Benutzereingaben

Ein weiterer wichtiger Bestandteil eines Programmes, der auch zu der GUI gehört, ist das Überprüfen der Eingaben vom Benutzer. Dazu gehören vor allem Eingaben in Textfeldern, aber auch Veränderungen von Listen, Comboboxen oder das Deaktivieren von Controls bei bestimmten Aktionen.

Man kann problemlos z.B. in seinem Programm implementieren, dass ein Textfeld nur Zahlen akzeptiert:

Private Sub Text1_KeyPress(KeyAscii As Integer)
        If InStr(1, "0123456789" + Chr(8), Chr(KeyAscii)) = 0 Then
               KeyAscii = 0
        End If
End Sub

Dies ist eine klare Lösung des Problems und sehr einfach nachzuvollziehen. Zur Technik: Es wird geprüft ob in dem String "012345679" plus Zeichen Nr. 8 (für Backspace=Zeichen löschen) das Zeichen, das gedrückt wurde, vorhanden ist. Wenn nicht wird der Parameter "KeyAscii" auf 0 gesetzt => kein Zeichen wird in die Textbox geschrieben.

Zugegeben, diese Funktion wäre natürlich in einem Algorithmus, der 10.000 mal pro Sekunde läuft, viel zu langsam. Aber da der Benutzer höchstens wenige mal in einer Sekunde eine Taste drückt, wären ein paar Bruchteile von Millisekunden an Performance-Verlust gegenüber einer C++ Funktion für den Benutzer nicht wahrnehmbar.

Ich hoffe, ich konnte deutlich machen, dass dieses "Geschrei" um die Performance in solchen Fällen der Programmierung völlig irrelevant ist. Eine sauber codierte VB-Funktion genügt in solchen Fällen völlig: Das Programm läuft wie gewünscht völlig korrekt und der Entwicklungsaufwand ist minimal.

3. Runtime-Files

Natürlich darf ich diesen Artikel nicht völlig kurzsichtig schreiben, und muss auch die andere Seite betrachten:

Visual Basic benötigen seit Version 1.0 Runtime-Dateien auf dem PC, auf dem sie laufen. Dies bedeutet, es muss eine bestimmte DLL Datei im Windows oder System Verzeichnis liegen, um das Programm auszuführen.

Ein praktisches Beispiel für einen Problemfall wäre ein Autostart-Programm für eine CD-ROM. Das Programm soll starten, wenn die CD eingelegt wird, auf einem beliebigen Computer. Nur steht ja nicht fest, ob die Runtime-Dateien auf diesem PC überhaupt installiert sind. Und es macht sicherlich keinen guten Eindruck, wenn schon der Autostart der Software mit einer Fehlermeldung à la "Runtime files not Found! Cannot run program!" abbricht.

Hier ist eventuell ein C++ Programm nicht nur ratsam sondern erforderlich, denn solche Programme benötigen nunmal keine Runtime-Dateien und werden auf jedem (Windows-) System starten (abgesehen von Programmen mit dynamischer Einbindung der MFC).

C++  

1. Für die Power:C++

Nun aber weiter in der Grundidee. Die Rede war ja von "Zusammenarbeiten" der Programmiersprachen. Wie ist dies nun möglich? Sicherlich gibt es hierfür mehrere Möglichkeiten, auch abhängig von der Herstellerfirma der Entwicklungs-Tools. Ich beschränke mich hier aber auf normale, generische Dynamic Link Libraries (DLLs). Man schreibt einfach alle Funktionen, für die wirklich Geschwindigkeit benötigt wird, als C(++) Code und exportiert die Funktionen in einer DLL. Diese DLL kann dann wiederum in Visual Basic mit

Declare Function XYZ Lib "MeineDLL.DLL" (Parameter As Integer) _
As Long

oder ähnlichem verwendet werden.

Dies klingt im ersten Moment etwas kompliziert; ist es zu Anfangs auch, aber wenn man sich daran gewöhnt hat, wird man wirklich erstaunliche Leistungen erzielen können.

2. Ein Beispiel

Anhand eines recht einfachen Beispieles möchte ich hier die oben beschriebene Technik verdeutlichen.

Wir schreiben einen sehr einfachen Verschlüsselungs-Algorithmus, der ein Passwort zum Verschlüsseln verwendet. Bei diesem Algorithmus wird dieselbe Funktion fürs Ver- und Entschlüsseln benutzt. Sind das Verschlüsselungs- und das Entschlüsselungs-Passwort ungleich, kommt als Entschlüsselungs-Ergebnis nicht mehr der Original-String heraus.

Technik:

  • Nehme ein Zeichen vom Original-String und ein Zeichen vom Passwort-String
  • Verknüpfe die ANSI-Werte der beiden Zeichen über XOR und schreibe sie in das Ziel-Array
  • Weiter bei Schritt 1 mit den nächsten beiden Zeichen
  • Ist das Ende des Passwort-Strings überschritten, beginne wieder beim ersten Zeichen vom Passwort-String.

Dieser Algorithmus lässt sich sowohl in VB als auch in C++ sehr einfach implementieren. Die C++ Funktion besteht sogar aus nur 2(!) Zeilen wirklichem Code. In unserem Beispiel würden wir sie etwa so schreiben (Visual C++):

__stdcall simpleencrypt(
        char *source,
        DWORD len,
    char *dest,
        char *pass,
        DWORD lenpass)
{
for (i=0;i<len;i++)
    dest[i] = source[i] ^ pass[i%lenpass];

return 0;
}

Argumente:

source ist ein Zeiger auf das erste zeichen im Original-String
len ist die Länge des Original-Strings
dest ist ein Zeiger auf das erste Zeichen im Ziel-String
pass ist ein Zeiger auf das erste Zeichen im Passwort-String
lenpass ist die Länge des Passwortes

Voraussetzung für diese Funktion ist, dass der Zielstring genug Platz für die selbe Anzahl an Zeichen wie der Original-String hat. Die ist aber wiederum keine sehr zeitaufwendige Aufgabe und kann in VB gelöst werden.

Zum Exportieren der Funktion in eine DLL Datei sollte im VC++ - Projekt eine "export.def" Datei angelegt werden, die "EXPORTS simpleencrypt" enthält.

Hier aber nun der entsprechende VB-Code dafür:

'In einem Modul
Public Declare Function simpleencrypt Lib "meinedll.dll" _
                (Source As Byte, ByVal Length As Long, Dest As _
                Byte, Pass As Byte, ByVal LenPass As Long) As Long

Public Function VBSimpleEncrypt(strSource As String, _
strPass As String) _
As String
Dim aSource() As Byte
Dim aDest() As Byte
Dim aPass() As Byte

aSource = StrConv(strSource, vbFromUnicode)
ReDim aDest(0 To UBound(aSource))
aPass = StrConv(strPass, vbFromUnicode)

Call simpleencrypt(aSource(0), UBound(aSource) + 1, _
aDest(0), aPass(0), _
UBound(aPass) + 1)

VBSimpleEncrypt = StrConv(aDest, vbUnicode)
End Function

Sie sehen, der Eingabe- und Passwort String werden in ein Byte-Array umgewandelt, sonst wären sie nicht kompatibel mit der C++-Funktion, und werden direkt an die DLL weitergereicht. Danach wird das Ergebnis wieder in einen VB-String zurückgewandelt und fertig ist der Aufruf! Eventuell benötigen sie in ihrem Programm gar nicht die String-Eingabe- und Ausgabeparameter, sondern nur pure Byte-Arrays, aber ich kann im Rahmen dieses Artikels nicht alle Möglichkeiten abdecken.

Um weitere Informationen über das Aufrufen von C-DLL Funktionen aus VB heraus zu bekommen, lesen sie bitte einen entsprechenden Artikel (ich habe das Thema in einem Artikel von mir schon einmal angerissen)!

3. Performancegewinn

Die obige C++ Funktion läuft ca. doppelt so schnell wie die schnellste VB-Funktion in einer voll durch-optimierten native-Code EXE Datei

Sicherlich hätten sie eventuell mehr erwartet, aber man muss bedenken, dass es sich hierbei um einen sehr einfachen Algorithmus handelt. Bei komplexeren Algorithmen, in denen mehr auf die langsamen VB-Funktionen zugegriffen wird, kann es zu 30-fachen, 40-fachen oder sogar noch höheren Geschwindigkeitsgewinnen kommen!

4. Umgewöhnung

Es ist sicherlich eine schwere Aufgabe für einen reinen VB-Entwickler, einige seiner Funktionen plötzlich in C++ schreiben zu müssen. Auch für mich persönlich war dies ein wirklich schwieriger Sprung. Ganz abrupt muss man auf alle liebgewonnenen VB-Funktionen verzichten, die einem alles so einfach gemacht haben. Zugegeben, es hat auch schon sehr komplexe VB-Funktionen gegeben, vor denen ich zurückgeschreckt bin und sie letztendlich nicht in C++ übersetzt habe. Meistens sind dies aber Funktionen, wo ein Geschwindigkeitsgewinn nicht dringend erforderlich ist.

Diese ganze Problematik bezieht sich selbstverständlich nicht auf ursprünglich reine C++-Programmierer, da diese ja sowieso daran gewöhnt sind.

Sicher ist aber: Wenn sie einmal in den Genuss einer schnellen C++ Funktion mitten in ihrem VB-Programm gekommen sind, werden sie danach süchtig werden, und es nur noch auf diese Art machen wollen ;-)

Alles, was drin ist: Assembler  

Nun kommen wir zu einem Teil dieses Artikels, den viele Programmierer wahrscheinlich getrost überspringen können.

Es geht um die Programmiersprache "Assembler". Mit ihr steuert man quasi direkt den Prozessor. Assembler kann man als "Grundsprache" des PCs bezeichen. Einen kompilierten C++ oder Basic Code kann man nicht in den Quellcode zurückverwandeln (abgesehen von VB3 P-Code), man kann aber jede .EXE, .DLL, .COM etc. Datei in Assembler-Code zurückverwandeln.

Der Vorteil von Assembler ist schnell erläutert: Kein Compiler kann den optimalsten Maschinen-Code für einen bestimmten Algorithmus generieren. Dies liegt ganz einfach daran, dass er die Aufgabe, die ein Algorithmus erfüllen soll, nicht kennt. Daher werden eventuell unnötige Befehle, zu zeitraubende Kopier-Arbeiten u.ä. verarbeitet.

Da Assembler-Code quasi 1:1 zu Maschinen-Code steht, steht man hier nicht vor diesem Problem. Man muss dem Computer zwar in seinem Programm-Code wirklich jede Anweisung für den Prozessor mitteilen, im Gegenzug kann man aber seinen Code perfekt an den zu implementierenden Algorithmus anpassen. So wird, bei einem guten Assembler-Code, im fertigen Programm kein Befehl mehr ausgeführt, der unnötig für die Problemlösung ist.

Ein weiterer großer Vorteil von Assembler: Man kann den Code problemlos z.B. in seine C++ Funktionen integrieren und auch dieselben Variablennamen und Sprungmarken benutzen. In Visual C++ funktioniert dies über die Block-Anweisung "__asm {}".

Als Beispiel möchte ich hier den einfachen Verschlüsselungsalgorithmus (s.o. für C++ Source Code) als Inline-Assembler-Code vorstellen:

__stdcall simpleencrypt(char *source, DWORD len, char *dest,
                                  char *pass, DWORD lenpass)
{
   __asm
  {

     mov ecx, len       ;ecx mit der Länge des Original-Strings laden
     mov ebx, pass      ;ebx mit Adresse des Passwortes laden
     mov edx, lenpass   ;edx mit Länge des Passwortes laden

     mov esi, source    ;esi mit Adresse des Quell-Strings laden
     mov edi, dest      ;edi mit Adresse des Ziel-Strings laden

     Schleife:

     mov al, [esi]      ;Quell-Zeichen in al kopieren
     mov ah, [ebx]      ;Passwort-Zeichen in ah kopieren

     mov [edi], al      ;Verschlüsseltes Zeichen in Ziel kopieren

     xor al, ah         ;Xor-en

     inc ebx            ;Position im Passwort um 1 erhöhen
     dec edx            ;Verbleibende Zeichen um 1 verringern

     jnz Weiter         ;Wenn noch nicht am Ende, springe zu Weiter

     ;Wenn doch
     mov edx, lenpass   ;Länge wieder holen
     sub ebx, edx       ;Position im Passwort wieder auf Anfang setzen


     Weiter:
     inc esi            ;Nächstes Byte im Quell-String
     inc edi            ;Nächstes Byte im Ziel-String


     dec ecx            ;Zähl-Register um 1 verringern
     jnz Schleife       ;Wenn nicht 0, Schleife wiederholen

   }

   return 0;
}

Der Code ist zwar relativ kompliziert, aber er läuft noch einmal ca. 4(!) mal schneller als die C-Code Funktion. Sicherlich ist der Code noch zu optimieren, es könnten z.B. immer 4 Bytes auf einmal ge-xor-t werden, aber darauf möchte ich hier nicht weiter eingehen.

Die alte C-Funktion kann direkt durch diese Funktion ersetzt werden, es gelten die gleichen Aufrufs-Konventionen und es kann auch die VB-Kapselfunktion (s.o.) benutzt werden.

Delphi  

Am Anfang dieses Artikels erwähnte ich, dass für mich Visual Basic und Delphi "dieselbe Art" von Programmiersprachen sind. Dies möchte ich hier kurz erläutern:

Mit beiden Programmen kann man schnell eine GUI und den nötigen Überprüfungscode erstellen (s.o.) und beide Programme haben im Performance-Vergleich gegen C keine Chance.

Delphi-Liebhaber mögen einwenden, dass sich mit Delphi viel eher "professionelle" Anwendungen entwickeln lassen als mit Visual Basic. Ich persönlich bin da anderer Meinung. Für mich ist es wirklich nur eine Frage des Geschmacks, ob man Delphi oder Visual Basic verwendet. Ich benutze Visual Basic, da ich BASIC als erste Programmiersprache gelernt habe und sehr viel mehr Erfahrungen mit Visual Basic habe.

Der schulische Aspekt  

Weiter oben erwähnte ich den schulischen Wert einer Programmiersprache. Hiermit ist gemeint, wie gut eine Programmiersprache für einen völligen Programmier-Neuanfänger geeignet ist.

Für mich gilt hier: Grundsätzlich gibt es auch hier keine "beste" Programmiersprache. Das eigentliche "Programmieren" ist nämlich nicht abhängig von einer bestimmten Sprache und deshalb sind theoretisch alle strukturierten Programmiersprachen hierfür geeignet.

Mögliche Kandiaten sind: Basic (Visual Basic), Pascal (Delphi), C++ (Visual C++) oder auch Java oder ähnliche. Beherrscht man erst einmal das Programmieren selbst, dauert es nur sehr kurze Zeit, eine neue Sprache nachzulernen.

Ich würde an dieser Stelle von C++ als Start-Sprache abraten. Diese Sprache ist wirklich sehr komplex und eventuell zu kompliziert für einen Neuanfänger. Ausgenommen, man kennt jemanden, der es gut beibringen kann, oder hat ein gutes Buch.

Gut geeignet ist Delphi und noch besser geeignet ist VB (Visual Basic). In VB brauch man sich zunächst einmal weniger Gedanken über Typen etc. machen und kann sich voll dem implementieren von Algorithmen widmen. Trotzdem würde ich einen erfahrenen Programmierer zu Rate ziehen, denn man kann sich in Visual Basic schnell einen sehr schlechten Programmier-Stil angewöhnen (ich spreche da aus Erfahrung!).

Nachwort  

Nun bin ich fast am Ende meiner Meinungs-Darlegung angekommen. Ich hoffe, es ist mir gelungen, einmal in kurzer Fassung mit einige Beispielen, mein Konzept des Programmierens hier vorzustellen. Außerdem ist dieser Kompromiss vielleicht endlich mal ein Schritt in der Streitfrage der "besseren" Programmiersprache.

Anregungen und Kommentare sind erwünscht. Bitte eMail an

Dokument: Der ewige Streit um Programmiersprachen, Version 1.00
Original-Url: http://www.krumsiek.com/artikel/programmiersprachen_i.html

Ihre Meinung  

Falls Sie Fragen zu diesem Tutorial haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.