www.thomas-guettler.de / Vorträge
niemand.leermann@thomas-guettler.de
Programmierung Allgemein
   Warum Programmieren?
1.    Einleitung
1.    Was ist ein Editor?
   Vergleich von mir bekannten Programmiersprachen
   Grundlegendes
   Versionsverwaltung
4.    Allgemein
4.    Begriffe
4.    CVS vs. SVN
4.    CVS
4.    SVN
4.5.     Ein lokales Repository anlegen
4.5.     SVN Tipps
   Tipps zu einzelnen Programmiersprachen
5.    C
5.    Python
   Warum ich von Perl nach Python umgestiegen bin
   Allgemeine Hinweise zur Programmierung
   32 vs 64 Bit
   Advanced Spass in the Linux Environment
10    Links

1 Warum Programmieren? [toc]

Warum sollte man sich Programmierung beschäftigen? Entweder man möchte ein konkretes Problem lösen, oder aus Interesse. Es gibt zwar für fast alle Problemstellungen fertige Programme, doch wenn man individuelle Wünsche hat, braucht man mehr als starre Fertigprodukte.

Wer Programmieren kann ist dem reinen Anwender weit voraus, denn der Computer lässt sich dann beliebig nach seinen Wünschen steuern. Otto Normalanwender hingegen muss oft das tun, was der Rechner möchte. Ein Texteditor ist ein Programm zur Bearbeitung von ASCII-Dateien. Unter Windows ist das z.B. Notepad und unter Unix der vi oder Emacs. Wer Programmieren lernen will muss mit einem Editor umgehen können. Programmierumgebungen wie Delphi oder Visual-Studio sind deshalb nicht zu empfehlen. Siehe auch Emacs Einführung.

2 Vergleich von mir bekannten Programmiersprachen [toc]

Die wahl der Programmiersprache ist nicht einfach, da es eine Unmenge an verschiedenen Sprachen gibt. Anfängern empfehle ich Python.

Mein subjektiver Vergleich verschiedener Programmiersprachen, mit dem Bezug zu meiner bevorzugten Sprache.
Java Ich habe lange mit Java entwickelt (u.a. meine Diplomarbeit). Das Kompilieren zu Bytecode ist umständlich. Außerdem ist Java nur kostenlos, aber nicht frei. Da es mehrere Java Compiler und Interpreter gibt, kommt es immer wieder zu Problemen. Während sich SUN damit beschäftigt Interfaces zu definieren, die dann von kommerziellen Anbietern implementiert werden, erstellen die Entwickler freier Programmiersprachen eine lauffähige Bibliothek.
C C ist rasend schnell in der Ausführung. Die Entwicklungszeit ist jedoch so langsam, dass ich nicht freiwillig in dieser Sprache programmiere. Der Einsatz von C ist nur bei betriebssystemnahen und zeitkritischen Aufgaben sinnvoll. Jeder, der sich ernsthaft mit Computern beschäftigt sollte dieser Sprache kennen. Debugging mit valgrind kann einem sehr viel Zeit sparen: Jeder Speicherzugriff wird von valgrind interpretiert und ggf. werden Warnungen auf stderr geschrieben.
C++ C++ hat gegenüber C mehrere Vorteile: Durch die Objektorientierung sind große Programme besser zu strukturieren. Exceptions (Ausnahmen) vereinfachen die Behandlung von Fehlern enorm. Trotzdem ist die Programmierung im Vergleich zu anderen Sprachen umständlich. Ein Grund dafür ist z.B., dass es keinen Garbage Collector gibt.
Lisp Lisp hat einige interessante Aspekte. Lisp hat den Nachteil, dass es viele verschiedene zueinander inkompatible Implementierungen gibt. Die auf Klammern beruhende und einfache Syntax ist eher für Maschinen als für Menschen geeignet.
Perl Perl ist Python sehr ähnlich. Da Perl-Code vieleSonderzeichen enthält, ist der Code nicht so leicht lesbar. Komplexe Programme werden in Perl unweigerlich "hässlich". Objektorientierung ist möglich, aber die Syntax ist grausam.
Ruby Als ich mit Sommer 2001 mit Perl und Java unzufrieden war, und eine neue Programmiersprache suchte, betrachtete ich Ruby und Python. Ruby fehlt bis heute integrierte Unicode Unterstützung. Außerdem ist Ruby nicht so verbreitet wie Python und es gibt weniger Module. Nachteilig find ich, dass der beim Aufruf einer Methode die Klammern weggelassen werden können. Das macht es schwierig zwischen der Methode und dem Methodenaufruf zu unterscheiden (aka Funktionspointer).
PHP PHP ist sehr verbreitet. Es wird hauptsächlich verwendet um auf einem Webserver HTML-Seiten für Browser zu erstellen. Bei PHP sehen Anfänger sofort einen Fortschritt: In wenigen Minuten ist eine einfaches Web-Formular erstellt. Der Einsatz außerhalb von Web-Anwendungen ist zwar auch möglich (z.B. gibt es eine Anbindung an die GUI-Bibliothek gtk), aber hier sieht man schnell, dass der Einsatz einer universellen Sprache sinnvoller ist.
TCL/TK TCL ist eine Scriptsprache, mit der hauptsächlich portable grafische Benutzeroberflächen programmiert werden. Die Syntax von TCL errinnert etwas an Shell-Scripte. Die Bibliothek TK kann auch mit Python programmiert werden (tkinter). TCL/TK wird kaum mehr weiterentwickelt. Für grafische Oberflächen empfehle ich PyGTK.
Shell Mittels Shell-Scripten lassen sich in wenigen Zeilen komplexe Aufgabenstellungen lösen. Werden die Scripte jedoch länger als 30 Zeilen, werden sie schnell unübersichtlich. Die meisten Scripte "fliegen einem um die Ohren" wenn Leer- oder Sonderzeichen in Dateinamen vorkommen. Man muss sich jedoch immer bewusst sein, dass es keine portablen Shell-Scripte gibt. Was mit der Bash unter Linux funktioniert, muss mit der Standard-Shell von Solaris noch lange nicht funktionieren.

Einige Gründe warum ich Shellscripte meide:
  • Keine Exceptions: Bei einem Fehler wird eine Meldung nach Standard-Error ausgegeben und mit der nächsten Zeile des Scripts weitergemacht.
  • Shellscripte sind selten portabel: Bash vs. ash/zsh, Linux vs. BSD, ...
  • Werden in einem Shellscript viele externe Programme gerufen (grep, cut, sort, sed, ...) werden die Scripte schnell langsam. Die Systemlast steigt, da viele neue Prozesse gestartet werden müssen.
Für den Embedded-Bereich (z.B. OpenWRT (Linux auf einem WLAN-Router)), sind Shellscripte gut geeignet, da z.B. Python zu groß ist. Ein einziges Binary (BusyBox) stellt eine Shell, und alle für ein Unix üblichen Befehle (awk, cat, chmod, chown, cp, crond, cut, date, dd, df, diff, ...) bereit.
Python Die Syntax ist sauber und einfach. Quelltext ist auch nach Jahren noch leicht lesbar. Die Objektorientierung ist pragmatisch gelöst. Nur in Ausnahmefällen greife ich zu einer anderen Sprache. Beispiel für eine Ausnahme: Ein Script soll nur einmal eingesetzt werden und lässt sich mit wenigen Zeilen mit der Shell (Bash) erledigen.

Resümee: Während bei Netzwerkprotokollen Standards wichtig sind, braucht man bei Programmiersprachen freie und funktionierende Implementierungen. Deshalb scheiden Lisp und Java aus. PHP, Perl, TCL haben eine unschöne Syntax. Bleibt die Shell (Bash) für kleine Scripte, Python für komplexe Programme und C für zeitkritische Dinge.

3 Grundlegendes [toc]

Hier ein paar Gedanken die allgemeingültig und unabhängig von der konkreten Programmiersprache sind.

4 Versionsverwaltung [toc]

Selbst wenn man alleine ein Programm schreibt, kann es sinnvoll sein eine Versionsverwaltung zu verwenden. Notwendig wird es, wenn mehrere Personen an einem Projekt arbeiten.

Unabhängig davon welches Programm zur Versionverwaltungs verwendet wird, ist es wichtig, dass man versteht welche Dateien versioniert werden müssen und welche nicht. Alle Dateien, die man per Hand bearbeitet müssen in die Versionsverwaltung. Das sind im besonderen Quelltexte und ggf. Konfigurationsdateien. Dateien die aus anderen Dateien erstellt werden, werden nicht versioniert. Ein paar Beispiele: Wenn man Änderungen an einem bestehenden Projekt durchführt, sollte man zusammengehörende Änderungen mit einem "commit" einchecken. Möchte man z.B. zwei unabhängige Veränderungen durchführen, ist es besser zweimal ein "commit" durchzuführen. Also: Erste Änderung, commit. Zweit Änderung, commit. Ansonsten lässt sich schlecht nachvollziehen warum die Änderungen durchgeführt wurden. Das Programm zur Versionsverwaltuns CVS ist weit verbreitet und den meisten Entwicklern bekannt. Es hat jedoch einige Nachteile, so dass für neue Projekte SVN (Subversion) verwendet werden sollte. Viele große Open Source Projekte sind in der letzten Zeit von CVS auf SVN umgestiegen.

Für beide Programme existiert das Programm "viewcvs". Es stellt das Repository mit Historie per Web dar. Man kann bequem verschiedene Versionen einer Datei mit einem Browser vergleichen. Eine GUI für CVS/SVN ist aus meiner Sicht nicht nötig. Die Befehle "commit" und "update" kann man auf der Shell ausführen.

Nachteile von CVS, die mit SVN behoben werden: Beispiele
   # Vergleicht die lokale Kopie mit der vor vier Tagen
   cvs diff -D "4 days ago" 

   # Vergleicht die lokale Kopie mit dem aktuellen Version im
   # Repository. Ohne die Options "-r HEAD" werden nur die Änderungen
   # angezeigt, die an der lokalen Kopie durchgeführt wurden.  

   cvs diff -r HEAD
Binäre Dateien im CVS:
  cvs status file     # Falls "Sticky Options: -kb", ist die Datei binär.
  cvs admin -kb file  # Als binär markieren.
  cvs update -A file  # In lokaler Kopie altes Flag löschen.

  Das "-kb" Flag für binäre Daten setzen, die nicht mit "cvs add -kb"
  eingecheckt wurden:

    FILES=`find . | grep -E '\.(png|gif|jpg)$'`
    cvs admin -kb $FILES
    rm $FILES
    cvs update
 cvs update
  -d --> Auch neue Verzeichnisse holen (wird sonst nicht gemacht!)
  -P --> Leere Verzeichnisse löschen. Ansonsten werden gelöschte
            Verzeichnisse immer wieder neu angelegt.
Mit der Datei .cvsrc lassen sich Optionen setzen, die dann immer automatisch gesetzt werden:
  ~/.cvsrc:
   log -N
   diff -u
   update -dP
   checkout -P
Das Verzeichnis 'mysite' und alle Dateien darunter sollen in die Versionsverwaltung augenommen werden. Bei SVN ist es üblich den aktuellen Stand in dem Verzeichnis 'trunk' zu pflegen.
# Dieses Verzeichnis enthält die zentrale Datenbank des Repositories
mkdir -p ~/svn/mysite

# Repository Verzeichnisse anlegen
svnadmin create ~/svn/mysite

# Suchen, ob noch Dateien vorhanden sind, die nicht
# versioniert werden sollen. Achtung: alle Dateien
# werden importiert.
find mysite 

mkdir  import_dir
mv mysite import_dir/trunk

# Es wird nur der *Inhalt* von import_dir
# importiert. Der Verzeichnisname ist also egal.
svn import import_dir file://$HOME/svn/mysite

# Original wird nicht mehr benötigt
mv import_dir tmp

# Trunk (Head) Arbeitskopie aus dem Repository holen, und
# in das Verzeichnis 'mysite' speichern.
svn co file://$HOME/svn/mysite/trunk mysite

5 Tipps zu einzelnen Programmiersprachen [toc]

Um bei einer fehlerhaften Assert-Anweisung, oder beim Unterbrechen des Programmes mit Strg-C automatisch einen Traceback mit Zeilennummern zu erhalten, kann man Folgendes verwenden (Nur unter Linux getestet, sollte auch mit anderen Unix-Systemen gehen):
/*

 Ausprobieren:
 gcc -g -Wall tbtest.c -o tbtest
 ./tbtest
  test NNNN

 Zweite Shell:
 kill NNNN

*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void print_backtrace() {
  char str[100+4096];
  char path[4096];
  path[readlink("/proc/self/exe", path, -1+ sizeof(path))] = '\0';
  sprintf(str, "echo 'bt\ndetach\nquit\n' | gdb -batch -x /dev/stdin %s %d\n",
          path, (int)getpid() );
  system(str);
  exit(2);
}


void signalhandler(int sig){
  printf("#Signal %i\n", sig);
  print_backtrace();
}

#undef assert
#define assert( expression )         \
  ( ( void ) ( ( expression ) ?                             \
               0 : my_assert( #expression, __FILE__, __LINE__ ) ) )

/* Print Stacktrace with line numbers if assert fails */
void my_assert(const char *expression, const char *filename,
              int line ){
  printf("Assertion failed %s %s %i\n", expression, filename, line);
  print_backtrace();
}

// .......
int main(int argc, char *argv[]) {
  signal(SIGTERM, signalhandler);
  signal(SIGINT, signalhandler);
  signal(SIGSEGV, signalhandler);
  while(1) {
	printf("testtb %d\n", getpid());
  }
}
Siehe Python Einführung.

6 Warum ich von Perl nach Python umgestiegen bin [toc]

Von 1998 bis 2001 war Perl meine bevorzugte Programmiersprache. Als ich jedoch eine Anwendung schreiben wollte, deren Datenstruktur aus vielen Referenzen zu ineinander verschachtelten Objekten bestand, ist der Perl-Mode von XEmacs ausgestiegen. Die Unmenge von Sonderzeichen hat er nicht verkraftet. Die Syntax war richtig, das Programm war lauffähig. Dass der Perl-Mode die Syntax nicht mehr verstand, war für mich der Anlass eine andere Programmiersprache zu suchen.

Im Folgenden ein paar Dinge, warum ich von Perl zu Python gewechselt bin: Mit "use strict;" lassen sich einige der Schwachstellen von Perl abschalten. Man kann jedoch nicht davon ausgehen, dass fremder Quelltext "use strict" verwendet.

Perl lässt sich trotz der Nachteile nicht ignorieren. Als Softwareentwickler muss man in der Lage sein Änderungen an Perl-Quelltext vornehmen zu können.

Perl wird wohl für immer ein geläufiger Begriff sein. Ähnlich wie "Uhu", "Padex", "Pampers" etc. nicht nur das Produkt einer Firma bezeichnen, sondern in der Umgangssprache auch stellvertretend für eine Gruppe von Produkten stehen, ist Perl der geläufige Begriff für "Scriptsprache".

Andere sind auch meiner Meinung: Warum nicht Perl in "A Byte of Python"

Trotzdem verwende ich Perl! Jedoch fast ausschließlich als Ersatz für sed und awk als Einzeiler.

7 Allgemeine Hinweise zur Programmierung [toc]

8 32 vs 64 Bit [toc]

Folgende Tabelle wurde mit dem C-Programm print_sizeof.c erstellt. Es werden die Speichergrößen der Datentypen zwischen 32 Bit und 64 Bit (amd64) verglichen (Linux, gcc).
 6432
char 1 1
int 4 4
unsigned int 4 4
long 8 4
unsigned long 8 4
long long 8 8
short int 2 2
unsigned short int 2 2
float 4 4
double 8 8
void* (Pointer) 8 4

9 Advanced Spass in the Linux Environment [toc]

Linux ist ein Eldorado für Programmierer.

10 Links [toc]


© 2004-2005 Thomas Güttler. Der Text darf nach belieben kopiert und modifiziert werden, solange dieser Hinweis zum Copyright und ein Links zu dem Original unter www.thomas-guettler.de erhalten bleibt. Es wäre nett, wenn Sie mir Verbesserungsvorschläge mitteilen: guettli@thomas-guettler.de