News   Magazin   Börse   Links   ArcArchie   Homepages
 Magazin  RISC OS & C-Programmierung 1: RISC OS und C Home 
Hardware   Software   Praxis   Sonstiges  
RISC OS & C-Programmierung 1: RISC OS und C  Alexander Ausserstorfer 2. 1. 2015

Die Programmiersprache C wurde ursprünglich in den Siebziger Jahren in Verbindung mit dem Mehrbenutzerbetriebssystem UNIX entwickelt. Das Ziel von C war es, den Programmcode möglichst hardwareunabhängig zu machen. Statt den kompletten Code für eine andere Umgebung, Plattform oder Rechnerarchitektur immer wieder neu schreiben zu müssen, übernahm das jetzt ein Programm. Dieses Programm wird Compiler genannt (Englisch to compile für sammeln, erstellen, zusammensetzen), da es verschiedene Quellen zu einem einzigen, großen Programm zusammenstricken kann. Damit reicht es im Idealfall aus, einmalig einen neuen Compiler zu schreiben, der den Quellcode in die jeweils endgültige Maschinensprache der Zielplattform oder verwendeten Rechnerarchitektur übersetzt.

Um in C programmieren zu können, braucht man daher diesen sogenannten Compiler. Für RISC OS gibt es drei solcher:

  • GCC
  • LCC
  • DDE

LCC wird nicht mehr weiterentwickelt. Bei DDE (Desktop Development Environment) handelt es sich um eine komplette Arbeitsumgebung, die in die Oberfläche von RISC OS integriert ist. Es bietet wesentlich mehr als nur einen C-Compiler und ist auf den ursprünglich von Norcroft für RISC OS entwickelten C-Compiler zurückzuführen. Daher auch unter der Bezeichnung Norcroft / Acorn C/C++ bekannt. DDE ist kommerziell erhältlich. [Anm. cms: DDE ist eine der wenigen Einnahmequellen von RISC OS Open Ltd. Wer ROOL unterstützen möchte ...]

GCC Logo GCC stand ursprünglich für GNU C-Compiler, wurde aber später um andere Programmiersprachen erweitert, weshalb die Abkürzung heute die Bedeutung GNU Compiler Collection erhalten hat. GNU ist eine von Richard Stallman, ehemaliger Mitarbeiter am Massachusetts Institute of Technology (kurz MIT) in den USA, in den Achtziger Jahren gegründete Softwareinitiative zur Schaffung eines freien Betriebssystems. Dieses Betriebssystem orientiert sich stark an UNIX.

Die Bezeichnung GNU steht für GNU's not UNIX. Es handelt sich dabei um ein rekursives Akronym, das heißt eine Abkürzung, die auf sich selbst verweist. Es handelt sich dabei außerdem um ein Paradoxon, da als rekursives Akronym die eigene Bedeutung undefiniert ist.

Bis Anfang der Neunziger Jahre waren große Teile dieses freien Betriebssystems fertiggestellt. Was allerdings noch fehlte, das war ein brauchbarer Betriebssystemkern. Diesen steuerte im September 1991 eher zufällig ein gewisser Linus Torwald aus Finnland bei. Der Kern ist unter dem Namen Linux bekannt geworden. Freie Betriebssysteme, welchen diesen Kern verwenden, werden heute in ihrer Gesamtheit meist generell als Linux bezeichnet, obwohl die restliche Software meist aus dem GNU-Projekt herstammt.

Der Compiler GCC wurde ursprünglich im Rahmen des GNU-Projekts entwickelt und ist damit sehr leistungsstark, frei und vor allem kostenlos verfügbar, da er ja gerade dazu gemacht worden ist, ein ganzes Betriebssystem zu schaffen. GCC wird auf Grund seiner Flexibilität gerne auch als Schweizer Taschenmesser bezeichnet. Allerdings ist der Einstieg damit nicht so leicht möglich wie mit DDE, da man sich bei GCC um vieles selbst kümmern muss.

Die Version von GCC für RISC OS ist zu finden unter www.riscos.info/index.php/GCC. Man benötigt insgesamt mindestens vier Dateien:

[Anm. cms: Je nach Bedarf kann man noch den C++ Compiler und Make herunterladen.] Am besten ist es, man schafft sich ein eigenes Verzeichnis namens GCC und entpackt den Inhalt der Dateien in dieses Verzeichnis. GCC muss mittels einem Doppelklick gestartet werden. Alternativ kann man das Programm in der Bootanwendung (!Boot -> Boot -> Run) bei jedem Bootvorgang automatisch starten. SharedLibs und UnixHome müssen dem System ebenfalls bekannt sein.

Auf dem Raspberry Pi (RISC OS 5.21 vom 4. Juni 2014) gibt es das Problem, dass das Modul SharedULib, zu finden in !Boot.Resources.!System.310.Modules, veraltet ist (Version 1.10). GCC lässt sich unter Verwendung dieses Moduls nicht starten. Es erscheint statt dessen die Fehlermeldung 'Clients still active' auf dem Schirm.

Daher muss diese Version durch Version 1.12 ersetzt werden. Die Version 1.12 ist zu finden unter www.riscos.info/downloads/gccsdk/sharedunixlib/system.zip.

Verzeichniss für GCC Hat man das System erfolgreich eingerichtet, kann man die Version des Compilers abfragen mittels dem Befehl

*gcc --version

Bei GCC spielt sich alles auf Kommandozeile-Ebene (Englisch CLI für command line interpreter) ab (vom Desktop aus Taste F12 drücken). Multitasking kann man höchstens mittels einem Task Window mit den Tasten Strg und F12 erzwingen, aber hierbei ist zu beachten, dass dem Task Window über 6 MB Speicher zugewiesen werden muss. Dies kann man erreichen, indem man im Task-Manager (Klick auf Raspberry-Pi-Symbol rechts unten) dem nächsten Programm (unter Application tasks -> next) den Balken auf über 6 MB aufzieht.

Dateien mit C-Quellcode erhalten auf anderen Systemen normalerweise die Abkürzung .c. Nun gibt es diese Art von Markierung für Dateitypen unter RISC OS nicht, zumal unter RISC OS Verzeichnisse mittels dem Punkt getrennt werden (unter UNIX oder Windows ist das stets ein Schrägstrich).

Daher gibt es bei der GCC-Version für RISC OS die Besonderheit, dass Dateien mit C-Quellcode in einem Verzeichnis abgelegt sein müssen, welches den Namen c trägt. Wichtig ist, dass sich dieses Verzeichnis im aktuellen Verzeichnis-Pfad befindet, möchte man nicht mit Variablen oder ganzen, absoluten Pfad-Angaben hantieren. GCC findet sonst den zu übersetzenden Quellcode nicht. Der aktuelle Verzeichnis-Pfad kann mittels

*Cat

angezeigt werden. In diesem Verzeichnis-Pfad muss nun das Verzeichnis c aufgeführt sein. Ist es dort noch nicht aufgeführt, muss es dort erzeugt werden.

Um ein erstes C-Programm zu schreiben, kann man folgendes Listing mit Hilfe eines Editors wie StrongED, Zap oder auch einfach nur Edit in eine Text-Datei eingeben:

#include <stdio.h>

main()
{
    printf("Hello World!\n");
}
						

Diese Datei speichert man unter dem Namen HelloWorld ins Verzeichnis c. Nun gibt man in der Kommandozeile

*gcc HelloWorld.c -o HelloWorld

ein. Nachdem der Compiler das Programm übersetzt hat, kann man dieses mittels

*HelloWorld

oder einem Doppelklick (Desktop) starten. Der Dateityp des erzeugten Programms ist ELF.

Im Quellcode wird gleich in der ersten Zeile die Library stdio.h eingebunden (Englisch library für Bibliothek). Bei einer Library handelt es sich um so eine Art Katalog mit bereits fertigen Programmen, denen man nur noch einige Daten zur Ausführung auf den Weg mitgeben muss. Diese Art von Programmen heißen Funktionen. Eine Funktion ist auch so eine Art Schnittstelle, weil sie bei ihrem Aufruf die Übergabe von Daten oder Parameter erwartet. In unserem Fall werden der Funktion printf() die Daten HelloWorld\n zur Ausführung übergeben. Die Funktion printf() schreibt die übergebenen Daten auf den Bildschirm.

Mit der Anweisung #include <stdio.h> werden sämtliche Funktionen, welche in dieser Library hinterlegt sind, dem Compiler nur bekanntgemacht. Der eigentliche, ausführbare Code, welcher beim Compilieren eingebunden wird, ist dagegen in einer gesonderten Library-Datei abgelegt. Diese Dateien weisen unter RISC OS die Endung /a auf.

GCC enthält bereits die Standard-Library stdlib. Die Funktionen dieser Library werden alle in einem über 1.000 Seiten dicken Handbuch beschrieben, welches online abrufbar ist. Weitere Libraries sind erhältlich und können ebenfalls eingebunden werden. So muss man sich nicht alles selbst schreiben, sondern kann bereits bestehende Funktionen in sein eigenes Programm mit einbinden. Da die Programmiersprache C sehr weit verbreitet ist, existieren auch sehr viele Libraries. Dies ist eine der Stärken von C. Zu beachten ist aber auch, dass eine Library immer plattformabhängig, das heißt von der verwendeten Hardware und dem verwendeten Betriebssystem abhängig ist.

Libraries bieten nur einheitliche Programmierschnittstellen. In unserem Beispiel heißt das, dass auf jedem System die Funktion printf() das Gleiche machen soll, nämlich die übergebenen Parameter auf den Bildschirm ausgeben. Wie das aber tatsächlich gemacht wird, ist auf jedem System anders, da verschiedene Systeme verschieden aufgebaut sind (sonst wären es ja keine verschiedenen Systeme). Aber genau deshalb braucht man die für sein System passende Library.

Um Funktionen aus Libraries zu nutzen, gibt es zwei Möglichkeiten.

Dynamisches Verlinken
Der Programmcode für die Funktion wird gesondert von den Programmen einmalig irgendwo im System hinterlegt und dann während des Programmablaufs angesprungen. Verschiedene Programme greifen damit während ihres Ablaufs auf den Programmcode an gleicher Stelle zurück. Der einmalig hinterlegte Programmcode der Funktionen wird eben als Library bezeichnet. Diese Technik ist auch unter dem Namen dynamisches Verlinken bekannt.

Sie hat den großen Vorteil, dass der Programmcode für die Funktionen nur einmalig vorhanden sein muss und damit Speicher gespart wird, da Programme klein gehalten werden können. Funktionen, welche häufig genutzt werden, werden so ausgelagert.

Nachteilig ist dagegen, dass gewisse Inkompatibilitäten entstehen können wie etwa wenn ein Programm nicht oder nicht richtig funktioniert, wenn die falsche oder eine zu alte Version der Library vorhanden ist.

In Windows wird diese Technik mit Hilfe von Libraries realisiert, welche die Endung .dll aufweisen (dll: Englisch für dynamic link library).

Unter RISC OS erfüllen die Module SharedCLibrary oder SharedUnixLibrary diese Funktion.

Man kann die Version der SharedCLibrary unter RISC OS in der Kommandozeile durch Druck auf F12 oder Strg-F12 und Eingabe von *Help sharedclibrary abrufen, jene der SharedUnixLibrary durch *Help sharedunixlibrary. Die entsprechenden Module müssen natürlich vorhanden bzw. vom System geladen worden sein. Sonst werden sie nicht gefunden.

Unter RISC OS existieren aus geschichtlichen Gründen zwei verschiedene Module:
Die SharedCLibrary wurde zusammen mit dem Compiler Norcroft/Acorn C/C++ eingeführt. Die SharedUnixLibrary entstand ursprünglich auf unixoiden Betriebssystemen und kam durch Portieren des Compilers GCC ebenfalls nach RISC OS, aber wohl erst später. Da Acorn der ursprüngliche Hersteller des Betriebssystems RISC OS war, war die SharedCLibrary natürlich favorisiert [Anm. cms: Da Teile von RISC OS in C geschrieben sind, muss die SharedCLibrary vorhanden sein und ist deshalb im ROM (*ROMModules) zu finden]. Mit ihrer Hilfe lässt sich auch kleinerer Programmcode als mit der SharedUnixLibrary erzeugen, aber dafür entspricht ihr Funktionsumfang nur dem ANSI-Standard und ist damit nicht so groß wie jene der SharedUnixLibrary.

Mit GCC lassen sich grundsätzlich Programme erstellen, welche die SharedUnixLibrary oder die SharedCLibrary verwenden. Als Standard, also ohne weitere Angabe, verwendet GCC jedoch die SharedUnixLibrary.

Der Dateityp eines mit GCC erzeugten Programms, welches die SharedUnixLibrary anspringt, ist ELF (Englisch für executable and linkable format). ELF ist ein Standard-Binärformat, das unter anderem auf vielen unoxiden Betriebssystemen verwendet wird (also unixähnliche Betriebssystemen, welche aber nicht mehr auf das ursprüngliche UNIX zurückzuführen sind, da sie völlig neu geschrieben wurden).

Statisches Verlinken
Die zweite Möglichkeit: Der Programmcode für die Funktion wird komplett ins Programm integriert oder mit eingebunden. In diesem Fall gibt es keine gesonderten Dateien, welche mehr angesprungen werden müssen. Diese Technik wird als statisches Verlinken bezeichnet. Programme dieses Dateityps sind ohne dem Modul SharedCLibrary oder SharedUnixLibrary ausführbar, aber dafür auch viel größer.

Standardisierung von C
Die Programmiersprache C verfügt nur über einen sehr kleinen, standardisierten Sprachwortschatz. Die eigentliche Mächtigkeit von C liegt aber in seinen Libraries begründet.

Viele C-Libraries nutzen unter der Haube entsprechende Funktionen des vorhandenen Betriebssystems. Wenn man in C die Funktion printf() in seinem Programm verwendet, wird unter RISC OS die entsprechende bereits im Betriebssystem vorhandene Betriebssystemroutine OS_Write0 zur Zeichenausgabe genutzt. Im Prinzip wird unter RISC OS vom C-Compiler nur die Funktion printf() auf OS_Write0 umgebogen. Auf anderen Systemen stehen andere Betriebssystemroutinen dahinter. Das macht man, damit ein C-Programmierer eine einheitliche Programmierschnittstelle hat und nicht jedes Betriebssystem neu erlernen und dann auch noch sein Programm umschreiben muss.

Hierbei gibt es in der Praxis jedoch Probleme. Libraries sind grundsätzlich immer hardware- und vom verwendeten Betriebssystem abhängig. Außerdem besteht oft noch eine Abhängigkeit zum verwendeten Compiler. Das heißt dass sich eine Library, welche für Compiler A geschrieben wurde, nicht einfach vom Compiler B verwenden lässt. Um so etwas zu erreichen sind oft (umfangreiche) Anpassungen notwendig.

Bestimmte Libraries setzten bestimmte Arbeitsumgebungen oder Compiler voraus. Sind diese nicht vorhanden, kann der Quellcode nicht compiliert werden.

Verschiedene Systeme unterscheiden sich hinsichtlich ihrer Architektur und damit auch hinsichtlich ihrer Möglichkeiten sowie ihren Vor- und Nachteilen. Will man diesen Systemen aber eine einheitliche, gemeinsame Programmierschnittstelle geben, stellt man diese Systeme gleich.

RISC OS etwa ist ein kooperatives Betriebssystem im Gegensatz zu Windows, Mac OS X oder GNU/Linux. Letztere sind preemptiv. Zwar sind preemptive Betriebssysteme sehr stabil, weil das Betriebssystem die Kontrolle über das System behält und abgestürzte Programme hinauswerfen kann (was bei RISC OS so nicht geht). Bei RISC OS ist das Multitasking aber viel einfacher und schlanker umgesetzt. Mit kooperativen und preemptiven Betriebssystemen existieren damit zwei Unterschiedliche Konzepte für Multitasking.

Diese Systeme müssen aber unterschiedlich programmiert werden, will man ihre jeweiligen Vorteile behalten. Mit einer einheitlichen Programmierschnittstelle verliert man unter Umständen diese Vorteile.

Eine einheitliche Programmierschnittstelle kann außerdem dazu führen, dass die Programme größer und damit auch langsamer werden, als tatsächlich für ihre Funktion notwendig wäre. Deshalb sind abstrakt geschriebene Programme oft wesentlich größer und langsamer als direkt für ein bestimmtes System geschriebene. Je komplexer die Systeme werden, desto stärker wird in der Regel das System ausgebremst. Dies hat nicht allein mit C, sondern auch mit den verwendeten Funktionen oder Schnittstellen zu tun.

Unter anderem deshalb haben sich heute in der Praxis verschiedene Libraries für unterschiedliche Systeme herausgebildet. Das bedeutet aber auch, dass ein in C erstelltes Programm gegebenfalls doch neu für ein anderes System geschrieben oder zumindest Teile davon angepasst werden müssen, wobei der Programmierer Detailwissen über die jeweils daran beteiligten Systeme benötigt. Damit geht jedoch die eigentliche Grundidee von C verloren.

Nun gibt es also standardisierte Libraries, die für viele verschiedene Betriebssysteme und Computer existieren und damit immer die gleichen Funktionen zur Verfügung stellen. Die Standard-C-Library, welche die Funktion printf() enthält, ist solch ein Beispiel. Diese Funktion kann auf so gut wie allen Compilern und unter allen Betriebssystemen verwendet werden, weil immer eine entsprechende Library existiert, welche diese Funktion zur Verfügung stellt.

Darüber hinaus gibt es aber auch Libraries, die nur für bestimmte Compiler, Hardware oder Betriebssysteme existieren, weil sie nur dort Sinn machen. Bindet man in seinen C-Quellcode Funktionen einer solchen Library ein, lässt sich auch ein in C verfasstes Programm unter Umständen nicht mehr einfach so auf einen anderen Rechner übertragen, sondern muss für ein anderes System neu geschrieben werden.

Das alles macht C für den Anfänger recht schwierig und zuweilen auch undurchsichtig. Wer mehr über die Programmiersprache C erfahren möchte, sollte hier inklusive dem freien Buch, an vielen anderen Stellen im Web oder in der Buchhandlung vorbeischauen.

 
Hier geht es zum nächsten Teil Aufruf von Betriebssystemroutinen.

Einen Fehler im Artikel gefunden, etwas unklar, Ergänzung oder ein Tipp? Einfach eine Nachricht schicken!

Name: *

EMail:

Text: *
Hardware   Software   Praxis   Sonstiges  
ArcSite   News   Magazin   Börse   Links   ArcArchie   Homepages