Exkurs: Zeichenkonvertierung

Konvertierung von Quellcode-Zeichenketten in C64-Zeichenketten

Warum konvertieren?

Da der C-Quelltext und der C64 unterschiedliche Zeichensätze verwenden, muss der cc65-Compiler eine Konvertierung vornehmen. In den C-Standards werden diese unterschiedlichen Zeichensätze „source character set“ und „execution character set“ genannt. Der cc65 verwendet ISO 8859-1 als „source character set“ (welcher in den ersten 128 Zeichen mit ASCII übereinstimmt) und (zumindest beim C64 als Zielsystem) PetSCII als „execution character set“.

Wie diese Umwandlung genau vorzunehmen ist, wird in den Standards nicht genau festgelegt, sondern dem Compiler überlassen. Lediglich die wichtigsten Zeichen müssen vom Compiler richtig konvertiert werden. Das trifft für die Zeichen des sogenannte „basic character set“ zu. Zu diesem Zeichenvorrat gehören z.B. die Buchstaben a-z, A-Z, die Ziffern 0-9 sowie die wichtigsten Sonderzeichen.

PetSCII ist eigentlich nicht ein einzelner Zeichensatz, sondern besteht aus zwei Zeichensätzen – einer für den Großbuchstaben/Grafikzeichen- und einer für den Klein-/Großbuchstaben-Modus. Wie Ihr sicherlich schon bemerkt habt, schalten vom cc65 erzeugte Programme automatisch in den zweiten Modus um, damit Groß- und Kleinbuchstaben verwendet werden können. Wenn wir nun ISO 8859-1 (bzw. ASCII) mit PetSCII (in der Klein/Groß-Variante) vergleichen, stellen wir fest, dass die Klein- und Großbuchstaben vertauscht sind. Dies ist also die erste Konvertierung, die der cc65 vornehmen muss, was er auch tut, sonst hätten unsere ersten Test-Programme auf dem C64 seltsam ausgesehen.

Die Sonderzeichen und Buchstaben in den oberen 128 Zeichen von ISO 8859-1 (und die Zeichen {, |, } und ~ aus ASCII) haben keine Entsprechungen in PetSCII und sollten daher besser nicht verwendet werden. Umgekehrt haben die grafischen Zeichen in PetSCII keine Entsprechung in ASCII oder ISO 8859-1 und können daher von C aus nicht (oder zumindest nur mit nicht-portablen und schwer nachzuvollziehenden Mitteln) angesprochen werden.

Ein Testprogramm

In C-Zeichenketten können verschiedene sogenannte Escape-Sequenzen verwendet werden. Eine davon, nämlich „\n“ für „newline“ haben wir schon ausgiebig benutzt. Die anderen (und ihre Umsetzung auf dem C64) werden wir uns nun in einem kleinen Test-Programm angucken:

#include <stdio.h>
 
int main(void)
{
    puts("Converted values for C char constants:");
    puts("======================================");
    puts("('/' stands for backslash)\n");
    printf("// (backslash):       $%02X ($5C on PC)\n",'\\');
    printf("/' (single quote):    $%02X ($27 on PC)\n",'\'');
    printf("/\" (double quote):    $%02X ($22 on PC)\n",'\"');
    printf("/? (question mark):   $%02X ($3F on PC)\n",'\?');
    printf("/f (formfeed):        $%02X ($0C on PC)\n",'\f');
    printf("/n (newline):         $%02X ($0A on PC)\n",'\n');
    printf("/b (backspace):       $%02X ($08 on PC)\n",'\b');
    printf("/v (vertical tab):    $%02X ($0B on PC)\n",'\v');
    printf("/a (alarm or bell):   $%02X ($07 on PC)\n",'\a');
    printf("/t (tab):             $%02X ($09 on PC)\n",'\t');
    printf("/r (carriage return): $%02X ($0D on PC)\n\n",'\r');
    puts("//->\"\\\" /'->\"\'\" /\"->\'\"\' /?->\"\?\"");
    puts("/f->\"\f\" /b->\"\b\" /n->\"\n\"");
    puts("/v->\"\v\" 1\v2  /a->\"\a\" 1\a2");
    puts("/t->\"\t\" 1\t2  /r->\"\r\" 1\r2");
}

Wenn dieses Programm mit der Version 2.12.0 auf dem C64 ausgeführt wird, erzeugt es die folgende Ausgabe:

In der oberen Hälfte zeigt das Programm die Hexadezimal-Codes, in die die Escape-Sequenzen umgewandelt werden, und zum Vergleich die auf dem PC üblichen Werte. In der unteren Hälfte wird dann der Effekt, den diese (Sonder-)Zeichen bei der Ausgabe haben, getestet.

Zunächst sehen wir, dass \', \“ und \? ganz ohne Konvertierung genau wie erwartet funktionieren, da die Zeichen in ASCII und PetSCII auf den gleichen Positionen liegen. Diese Sequenzen brauchen wir auch gelegentlich, da wir sonst z.B. keine doppelten Anführungszeichen in Zeichenketten verwenden könnten, da sie ja gerade verwendet werden, um die Zeichenkette einzuschließen. Die Sequenz
für den Backslash wird ebenfalls nicht konvertiert, was auf dem C64 zu einem £ führt, da dieser keinen Backslash im Zeichensatz hat und an dieser Stelle das Pfund-Zeichen codiert.

Die Sequenzen \a (gibt normalerweise einen kurzen Ton aus oder lässt den Bildschirm aufblinken) und \t (Tabulator) werden ebenfalls nicht konvertiert. Die entsprechenden Codes in PetSCII haben aber einfach überhaupt keine Bedeutung. Hierbei fällt auf, dass Zeichen unterschiedlich behandelt werden, je nachdem, ob sie in der ausgegebenen Zeichenkette in Anführungszeichen stehen oder nicht. Dies liegt daran, dass die erzeugten Programme die Ausgaberoutinen des C64-Kernal verwenden und dieser (wie in BASIC) einen speziellen Modus innerhalb von Anführungszeichen verwendet.

Die Sequenzen \b, \f und \v werden anscheinend auf entsprechende Codes in PetSCII konvertiert. Der Backspace \b ergibt den Code für Inst/Del, welches auf dem C64 ja den erwünschten Effekt hat, das vorherige Zeichen zu löschen. Der Formfeed \f wird in den Code für Clr/Home übersetzt, welcher an den Bildschirmanfang springt. Der sogenannte vertikale Tabulator \v schließlich wird in Cursor down konvertiert. Bei \f und \v tritt wieder der Effekt ein, dass innerhalb von Anführungszeichen etwas anderes passiert als außerhalb.

Eine besondere Beachtung verdienen \n und \r. Diese haben auf dem PC (in ASCII) normalerweise die Bedeutungen LF ($0A oder dezimal 10) und CR ($0D oder dezimal 13) und haben beide etwas mit dem Zeilenende zu tun. Traditionell hatten Drucker und andere Ausgabegeräte getrennte Sonderzeichen/Befehle für den Wagenrücklauf an den Zeilenanfang (carriage return, CR) und das Vorschieben um eine Zeile (linefeed, LF). Aus diesem Grund haben Textdateien unter DOS und Windows und einige Internet-Protokolle immer noch beide Zeichen an den Zeilenenden (in der Reihenfolge CRLF). Unter Unix (der Heimat von C) wird dagegen nur LF als Zeilenende-Zeichen verwendet (und auch von der Return-Taste erzeugt). Auf dem C64 (und Apple-Computern bis zu MacOS 9) wird CR als Zeilenende-Zeichen (und Code der Return-Taste) verwendet.

Daher tauscht die Konvertierung des cc65 die Codes für \n und \r aus. Damit bleiben Programme zwischen Unix und C64 portierbar: \n bedeutet in beiden Fällen ein Zeilenende und den von der Return-Taste gelieferten Code. \r hingegen hat auf dem C64 überhaupt keinen Effekt (ähnlich wie \a und \t), während auf Unix-Systemen tatsächlich an den Anfang der gleichen Zeile gesprungen wird. Normalerweise sollte also einfach (wie in C üblich) \n verwendet werden, wenn Zeilenende oder Return gewünscht ist. (Zu Problemen kann es nur kommen, wenn man mit cc65 direkt DOS- oder Unix-Textdateien oder Internetprotokolle bearbeiten möchte. Hierbei müssen die in C sonst üblichen Sequenzen getauscht werden: CRLF wird durch \n\r (üblicherweise \r\n) und LF durch \r (üblicherweise \n) erreicht.)

Zusammenfassung

Aus den vorherigen Betrachtungen wird deutlich, dass in cc65-Zeichenketten normalerweise nur die Buchstaben und Zeichen des ASCII-Zeichensatzes (außer {, |, } und ~) und die Escape-Sequenzen \', \“, \? und \n vorkommen sollten. \b ist in Ausgaben weniger sinnvoll, aber für die Bearbeitung von Eingaben interessant.

Die anderen Zeichen und Escape-Sequenzen haben auf dem C64 entweder keine Entsprechung oder sind wegen der unterschiedlichen Behandlung in Anführungszeichen und der unterschiedlichen Interpretation auf anderen Systemen kritisch.

ckurs/exkurse/zeichenkonvertierung.txt · Zuletzt geändert: 11/05/2009 12:59 (Externe Bearbeitung)
www.chimeric.de Creative Commons License Driven by DokuWiki Recent changes RSS feed