Die Suche ergab 238 Treffer

von bbock
31.03.2023, 13:46
Forum: Programmierung
Thema: Programmieren in C mit dem z88dk
Antworten: 20
Zugriffe: 103591

15. Arbeiten mit Dateien 2

Diesmal wollen wir eine Textdatei einlesen, verarbeiten und das Ergebnis in eine zweite Textdatei ausgeben. Die Eingabedatei ist eine CSV-Datei, allerdings mit Semikolon als Trennzeichen statt Komma. Die Datei enthält Informationen über die Hauptstädte der Erde; die Daten stammen aus Wikipedia. Zur Vermeidung unnötiger Probleme habe ich sie um Sonderzeichen bereinigt.

Die Datei hat den Namen hauptst.csv und enthält die Felder Staat, Hauptstadt, Einwohner, Stand und Quelle. Wir wollen daraus eine Datei erstellen, die zu jeder Hauptstadt die Anzahl ihrer Einwohner im Format <Hauptstadt>: <Anzahl Einwohner> ausgibt.

Dazu öffnen wir zunächst die Eingabe- und die Ausgabedatei. Dann lesen wir in einer Schleife Zeile für Zeile ein, verarbeiten die Zeile und schreiben das Ergebnis in die Ausgabedatei. Zuletzt schließen wir beide Dateien.

Beginnen wir mit der Funktion main(), wo wir zuerst die benötigten Variablen deklarieren:

Code: Alles auswählen

/* Main
 */
int main(void) {
    char filename[13];
    char filenameOut[13];
    FILE *fp;
    FILE *fpOut;
    char buf[100];
    t_line line;
Die beiden Arrays für die Dateinamen sind 13 Zeichen lang; das genügt für 8.3-Dateinamen plus das String-Ende-Zeichen '\0'. Wenn man noch eine Laufwerksangabe etc. unterbringen möchte, dann muss man die Arrays natürlich entsprechend größer dimensionieren. Es folgen zwei file pointer, ein Puffer für die aktuell eingelesene Zeile und eine Variable für das Ergebnis der verarbeiteten Zeile mit den einzelnen Feldern. Letztere definieren wir folgendermaßen mit typedef:

Code: Alles auswählen

typedef struct {
    char staat[60];
    char hauptstadt[50];
    char einwohner[12];
    char stand[10];
    char quelle[40];
} t_line;
Alle Felder sind als char-Arrays definiert, weil eine Textdatei nun einmal Textzeichen enthält. Nun könnte man argumentieren, dass die Anzahl der Einwohner doch eigentlich eine Zahl ist und man besser einen Zahlentyp verwenden sollte. Aber das brauchen wir nur dann, wenn wir damit Berechnungen anstellen wollen, wie z.B. die Summe der Einwohner aller Hauptstädte zu ermitteln. Für unseren Anwendungsfall brauchen wir das nicht, also verzichten wir auf eine Typumwandlung.

Wir öffnen die Eingabedatei:

Code: Alles auswählen

    strcpy(filename, "hauptst.csv");
    fp = fopen(filename, "r");
    if (fp == NULL) {
        printf("Fehler: Eingabedatei %s nicht gefunden!\n", filename);
        return -1;
    }
Wir kopieren die String-Konstante "hauptst.csv" in die Variable filename, weil wir sie weiter unten nochmal benötigen und wir den Dateinamen nicht doppelt in den Quellcode schreiben wollen. Dafür gibt es auch noch andere Lösungen. Die Datei wird wieder mit fopen geöffnet, hier im Modus "r" (für "read"). Der resultierende file pointer fp kann in der Folge nur für Leseoperationen verwendet werden. Liefert fopen einen NULL-Pointer zurück, dann ist das Öffnen fehlgeschlagen, was wir mit einer Fehlermeldung und dem Rücksprung ins Betriebssystem mit dem Fehlercode -1 quittieren.

Die Ausgabedatei wird ganz ähnlich geöffnet:

Code: Alles auswählen

    strcpy(filenameOut, "extrakt.csv");
    fpOut = fopen(filenameOut, "w");
    if (fpOut == NULL) {
        printf("Fehler: Konnte Ausgabedatei %s nicht oeffnen!\n", filenameOut);
        fclose(fp);
        return -1;
    }
Hier verwenden wir den Modus "w" (für "write") und öffnen die Datei damit zum Schreiben. Ergo sind mit fpOut nur Schreiboperationen möglich. Die Fehlerbehandlung ist ähnlich der bei der Eingabedatei, allerdings dürfen wir hier nicht vergessen die Eingabedatei zu schließen, bevor wir zum Betriebssystem zurückkehren, denn diese ist zu diesem Zeitpunkt ja bereits geöffnet.

Die Schleife für das Lesen der Zeilen sieht folgendermaßen aus:

Code: Alles auswählen

    // Zeilen lesen
    while (fgets(buf, sizeof buf, fp) != NULL) {
        printf(".");

        // Zeile in Felder aufteilen
        parseLine(buf, &line);

        // Hauptstadt und Einwohner schreiben
        fprintf(fpOut, "%s: %s\r", line.hauptstadt, line.einwohner);
    }

    putchar('\n');
Die Funktion fgets liest eine ganze Zeile ein. Die maximale Länge der Zeile wird dabei durch die Länge des Puffers buf begrenzt, die wir mit sizeof buf ermitteln. Der Compiler-Operator sizeof ermittelt die Größe einer Variablen zur Compile-Zeit. Hier liefert er den Wert 100. fgets liefert einfach den ersten Parameter, also buf, zurück, es sei denn, wir sind am Dateiende angekommen: dann liefert fgets NULL zurück, was wir als Schleifenende-Kriterium verwenden.

Die Ausgabe eines Punkts pro Zeile soll nur etwas visuelles Feedback für das Lesen der Zeilen geben. Die Funktion parseLine soll dann die Zeile in die Felder Staat, Hauptstadt, Einwohner, Stand und Quelle aufteilen und das Ergebnis in die Struktur line schreiben. Der typedef für die Struktur sieht so aus:

Code: Alles auswählen

typedef struct {
    char staat[60];
    char hauptstadt[50];
    char einwohner[12];
    char stand[10];
    char quelle[40];
} t_line;
Schließlich werden die Felder Hauptstadt und Einwohner via fprintf in die Ausgabedatei geschrieben. Das putchar soll nur einen Zeilenumbruch nach den vielen Punkten ausgeben, damit der Cursor nach Beendigung des Programms wieder am Zeilenanfang steht, wo dann der Prompt des Betriebssystems erscheint.

Am Ende von main() müssen wir noch die Dateien schließen:

Code: Alles auswählen

    fclose(fp);
    fclose(fpOut);

    return 0;
}
Jetzt fehlt noch die Funktion parseLine zum Aufteilen der eingelesenen Zeilen:

Code: Alles auswählen

/* Zerlegt eine Zeile in Felder.
 */
char *parseLine(char *buf, t_line *line) {
    int i;
    int len;

    initLine(line);

    buf = parseToken(buf, line->staat, ';');
    buf = parseToken(buf, line->hauptstadt, ';');
    buf = parseToken(buf, line->einwohner, ';');
    buf = parseToken(buf, line->stand, ';');
    buf = parseToken(buf, line->quelle, ';');
}
Zunächst wird die Struktur line initialisiert. Beim Aufruf von parseLine hatten wir die Adresse der Struktur mit &line als zweiten Parameter übergeben. Wir haben jetzt also einen Pointer auf die Struktur. Den übergeben wir an initLine, um die Struktur zu initialisieren. initLine setzt nur das erste Zeichen aller char-Arrays auf '\0' und erzeugt damit leere Strings. Nota bene: das erste Zeichen eines Arrays ist in C immer das Zeichen mit dem Index 0!

Code: Alles auswählen

void initLine(t_line *line) {
    line->staat[0] = '\0';
    line->hauptstadt[0] = '\0';
    line->einwohner[0] = '\0';
    line->stand[0] = '\0';
    line->quelle[0] = '\0';
}
So, die Felder sind leer, also können wir sie jetzt mit den Daten der aktuellen Zeile füllen. Das erledigt die Funktion parseToken, die den char-Pointer buf sukzessive weiterschaltet, bis alle fünf Felder eingelesen sind. buf zeigt also immer auf den Anfang des nächsten Feldes im Puffer. Man beachte, dass die Parameter-Variable buf eine eigene lokale Variable der Funktion parseLine ist. Wenn wir sie verändern, dann wird die gleichnamige Variable buf der Funktion main() nicht verändert!

Code: Alles auswählen

/* Liest ein Feld bis zum Trennzeichen.
 * Gibt einen Zeiger auf das naechste Feld zurueck.
 */
char *parseToken(char *start, char *field, char delimiter) {
    while (*start != delimiter && *start != '\0') {
        *field++ = *start++;
    }
    *field = '\0';

    return ++start;
}
In der while-Schleife wird Zeichen für Zeichen aus dem Puffer in die jeweilige Feld-Variable aus der Struktur line kopiert, bis wir das Trennzeichen oder das String-Ende finden. Das Kopieren könnten wir mit der Anweisung *field = *start durchführen; anschließend müssten wir noch die beiden Pointer weiterschalten. Die hier gezeigte Variante führt die Zuweisung durch und schaltet anschließend die Pointer weiter - alles auf einmal. Nach der Schleife zeigt start auf das Trennzeichen, daher das Inkrementieren vor dem return.

Einige Dinge hätte man auch anders machen können. So wäre es z.B. möglich ohne Kopieren der Strings auszukommen, indem man '\0'-Zeichen in den Puffer schreibt, wo die Trennzeichen sind. Oder man hätte mit strtok arbeiten können - eine String-Funktion, die Tokens anhand von Trennzeichen ermittelt. Diese hat allerdings den Nachteil, dass sie aufeinanderfolgende Trennzeichen wie eines behandelt. Das taugt nichts, wenn Felder auch leer sein können.

Auch die Struktur wäre nicht unbedingt nötig. Man könnte stattdessen mit separaten Array-Variablen arbeiten, die nicht zu einer Struktur zusammengefasst sind. Dann hätte man allerdings auch alle Felder einzeln als Parameter an die Unterfunktionen übermitteln müssen - oder man hätte die Arrays gleich global gemacht. Letzteres ist aber wegen des "information hiding"-Prinzips in der Software-Entwicklung nicht wünschenswert.

Hier ist noch das fertige C-Programm und die Eingabedatei zum Download:

file_io_2.zip
file2.c und hauptst.csv
(4.85 KiB) 2751-mal heruntergeladen

Das ganze wird kompiliert mit

Code: Alles auswählen

zcc +cpm -subtype=pcw80 file2.c -o file2.com
von bbock
27.03.2023, 11:28
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 505270

Re: Fragen und Antworten zum C-Kurs

Die fehlenden Klammern werden nicht als Fehler moniert, weil der Funktionsname auch ohne die Klammern syntaktisch korrekt ist: es handelt sich dann um einen function pointer, also einen Zeiger auf eine Funktion. Ohne Zuweisung macht sie wenig Sinn, ist aber auch nicht falsch.
von bbock
26.03.2023, 13:39
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 505270

Re: Fragen und Antworten zum C-Kurs

Paul hat geschrieben: 25.03.2023, 11:33 ...Bitte verrate noch wie ich die ganzen Form3 Sachen übersetzen kann.
zcc +cpm -subtype=pcw80 -lndos -create-app forms3tst.c -o forms3tst.com
hat nicht funktioniert
forms3tst.c:83:15: fatal error: Too few arguments to call to function 'initForms'
Compilation aborted
Das Forms3-Projekt ist für Fortgeschrittene. :D Es besteht aus mehreren C-Dateien, du hast aber nur eine kompiliert. Der korrekte Aufruf ist:

zcc +cpm -subtype=pcw80 -lm -DAMALLOC -create-app forms3.c input2.c convert.c box.c forms3tst.c -o f3test.com

Hier wird eine Liste von C-Dateien als Quelle übergeben, die Mathematik-Bibliothek eingebunden und die automatische, dynamische Speicherverwaltung aktiviert. Du kannst forms3tst.c durch forms3tst_2.c ersetzen, dann mit z.B. f3test2.com als Ausgabedatei, um das zweite Beispiel zu übersetzen.
Paul hat geschrieben: 25.03.2023, 11:33 Davon abgesehen hatte ich das CLS schon versucht. Dazu fand ich ein funktionierendes Beispiel:

Code: Alles auswählen

/*
 *	Test the Native Console of the Amstrad PCW
 *
 *	23/3/2021 RobertK (based on ansivt52.c by Stefano)
 *
	Manual Index:
	https://www.manualslib.com/manual/1002846/Amstrad-Pcw8256.html?page=170#manual

	Character Set:
	https://www.manualslib.com/manual/1002846/Amstrad-Pcw8256.html?page=283#manual

	Terminal codes:
	https://www.manualslib.com/manual/1002846/Amstrad-Pcw8256.html?page=308#manual
 */

#include <stdio.h>

void main()
{
    int x;

    printf("Before CLS\n");
    printf("\x1b\x45");	 // ESC E -> Clear screen
    printf("\x1b\x48");  // ESC H -> Home
    printf("If this is the first thing you can read, CLS is OK.\n");

    /* Draw an X */
    for (x = 0; x < 11; x++) {
		// ESC Y r c -> gotoxy
		printf("\x1b\x59%c%c*",32 + 10 + x, 32 + 20 + x);
		printf("\x1b\x59%c%c*",32 + 20 - x, 32 + 20 + x);
    }
}
Übersetzt mit zcc +cpm -subtype=pcw80 -lndos -create-app screen.c -o screen.com

Ich habe dann versucht das selber umzusetzen:

Code: Alles auswählen

#include <stdio.h>

void gotoXY(unsigned int x, unsigned int y) {
    putchar(27);        // ESC
    putchar('Y');       // cursor to position
    putchar(y + 32);    // row + 32
    putchar(x + 32);    // column + 32
}
void cLS() {
    printf("Before CLS\n");
    printf("\x1b\x45");	 // ESC E -> Clear screen
    printf("\x1b\x48");  // ESC H -> Home
    printf("Test\n");
 /* putchar(27);       // ESC
    putchar(69);       // cls
    putchar(27);       // ESC
    putchar(72);       // home
*/
}

int main(void) {
	cLS;
    putchar('A'); // oder printf("%s", "O");
    gotoXY(1,1);
    putchar('B'); // oder printf("%s", "O");
    gotoXY(2, 2);
    putchar('C'); // oder printf("%s", "O");
    gotoXY(14, 14);
    putchar('O'); // oder printf("%s", "O");
    gotoXY(80, 26);
    putchar('Z'); // oder printf("%s", "O");
}
Übersetzt mit zcc +cpm -subtype=pcw80 -lndos -create-app PrintAT.c -o PrintAT.com

Das funktioniert nicht.
es macht zwar HOME, aber der Bildschirm ist nicht leer.
Ich habe dann versucht die Printf vorher und hinterher hinzuzufügen.
Die werden aber auch nicht ausgegeben :cry:
In C braucht jeder Funktionsaufruf Klammern, auch wenn die Funktion gar keine Argumente hat. In der ersten Zeile von main muss es also cLS(); heißen.

Das Home und das Clear screen kann man übrigens auch in einem einzigen printf machen.

Die Escape-Sequenzen stammen aus der Terminal-Emulation, und die ist im Joyce-Handbuch beschrieben. Hast du denn kein Joyce-Handbuch (eigentlich gibt es ja zwei)? Das ist z.B. im "90 GB"-Download von Dieter enthalten (unter Literatur > Manuale > System, glaube ich). Dort schau mal unter "Anhang III - Eigenschaften des Bildschirms" nach. Unter "ESC E" steht da: "Löscht das Darstellungsfeld. Die Position des Cursors bleibt davon unberührt."
von bbock
25.03.2023, 10:35
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 505270

Re: Fragen und Antworten zum C-Kurs

Paul hat geschrieben: 25.03.2023, 08:45 ...
Jetzt werde ich gierig. Ein CLS wäre dabei noch sehr praktisch ;)
und die Zeichen um Rahmen zu malen :ugeek:
Hierzu möchte ich dich auf mein Forms3-Modul hinweisen: viewtopic.php?p=645#p645
In forms3.zip findest du input.h und input.c mit einigen nützlichen Funktionen und Definitionen, u.a. clearScreen(). Wenn du Rahmen malen möchtest, benötigst du eine Zeichentabelle, die du im Joyce-Handbuch findest. Oder du siehst dir mal box.h und box.c an; da ist bereits eine fertige Funktion zum Zeichnen von Rahmen drin (drawBox).

Sieht so aus, als würdest du bereits an einem eigenen Projekt basteln?
von bbock
25.03.2023, 10:27
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 505270

Re: Fragen und Antworten zum C-Kurs

Paul hat geschrieben: 25.03.2023, 08:43 ...
Leider gibt die Joyce kein ü aus.
Wie bekomme ich Umlaute und sz auf der Joyce ausgegeben?
Irgendwo hatte Bernd einen Trick verwendet der funktionierte. Ich habe ihn jetzt nicht wiedergefunden und damals nicht wirklich verstanden.
Nehmen wir mal an, du möchtest das Wort "Größe" ausgeben - da ist sowohl ein Umlaut als auch das "scharfe S" drin. Das könntest du so machen:

Code: Alles auswählen

#define CH_SZ        126
#define CH_LC_OUML   124
...
printf("Gr%c%ce", CH_LC_OUML, CH_SZ);
Die beiden "%c"-Platzhalter stehen jeweils für ein Zeichen; diese werden durch die weiteren Parameter CH_LC_OUML (= 124) und CH_SZ (= 126) ausgefüllt. Das sind die Zeichen-Codes für "ö" und "ß".
von bbock
24.03.2023, 14:07
Forum: Programmierung
Thema: Programmieren in C mit dem z88dk
Antworten: 20
Zugriffe: 103591

14. Arbeiten mit Dateien

Der Zugriff auf Dateien erfolgt in C immer nach dem Muster Öffnen - Dateioperationen - Schließen. Die Dateioperationen werden im z88dk standardmäßig dazugebunden; braucht man sie nicht, dann kann man sie mit der zcc-Option -lndos weglassen, wodurch die ausführbare COM-Datei dann etwas kleiner wird. Möchte man die Dateifunktionen verwenden, dann bindet man sie in der C-Datei mit #include <stdio.h> ein.

Sehen wir uns die drei Schritte des Dateizugriffs anhand der zugehörigen Funktionen an:
  1. Öffnen
    Eine Datei öffnet man mit der Funktion fopen. Sie erwartet zwei Parameter: den Dateinamen und den Modus. Letzterer gibt u.a. an, ob man die Datei zum Lesen oder Schreiben öffnen möchte. fopen liefert einen Pointer auf eine Variable vom Typ FILE zurück. Diesen Pointer braucht man für alle weiteren Dateioperationen.
  2. Dateioperationen
    Es gibt mehrere Funktionen, um etwas mit Dateien zu machen. So kann man Daten lesen mit fgetc, fgets, fscanf oder fread. Oder man kann Daten schreiben mit fputc, fputs, fprintf oder fwrite. Welche Funktion man verwendet, hängt vom jeweiligen Anwendungsfall ab.
  3. Schließen
    Nach erfolgter Bearbeitung muss man die Datei schließen. Das ist unbedingt erforderlich, sonst hat man ein Speicherleck und man kann sogar Daten verlieren. Das Schließen bewerkstelligt die Funktion fclose, die nur den FILE-Pointer als Parameter verlangt.
Erzeugen wir mal eine kleine Textdatei. Dazu speichern wir folgendes Programm als file1.c:

Code: Alles auswählen

#include <stdio.h>

main() {
   FILE *fp;

   fp = fopen("hello.txt", "w");
   fputs("Kommt ein Pferd in eine Bar...", fp);
   fclose(fp);
}
Wir erzeugen eine COM-Datei mit folgender Befehlszeile:

Code: Alles auswählen

zcc +cpm -subtype=pcw80 file1.c -o file1.com
Wenn wir nun file1.com starten, dann wird die Datei hello.txt erzeugt. Deren Inhalt können wir uns mit type hello.txt anzeigen lassen.
von bbock
24.03.2023, 12:49
Forum: Programmierung
Thema: fnplot - Funktionsplotter
Antworten: 0
Zugriffe: 41348

fnplot - Funktionsplotter

Das Programm fnplot zeichnet mathematische Funktionen, die der Benutzer nach Belieben eingeben kann, wie z.B. f(x) = sin(2*x) * cos(x). Es verwendet die Bibliotheken Forms3 für die Benutzereingaben und TinyExpr für die dynamische Auswertung der Funktionen.

Die Skalierung der X- und Y-Achse ist frei einstellbar; man gibt jeweils den minimalen und maximalen x- und y-Wert an. Die Funktion selbst wird so eingegeben, wie man es in C oder anderen Programmiersprachen tun würde. Das "f(x)=" ist bereits vorgegeben; für obiges Beispiel gibt man also nur "sin(2*x) * cos(x)" ein (ohne die Anführungszeichen). Die Funktion wird in eine spezielle Datenstruktur kompiliert, damit sie sehr schnell berechnet werden kann - fast so schnell, als hätte man sie gleich fest in das C-Programm geschrieben.

Download: viewtopic.php?p=813

fnplot2.png
fnplot2.png (9.77 KiB) 41348 mal betrachtet
fnplot1.png
fnplot1.png (12.31 KiB) 41348 mal betrachtet
von bbock
19.03.2023, 11:11
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 505270

Re: Fragen und Antworten zum C-Kurs

kurt hat geschrieben: 19.03.2023, 10:37 Ich häng' mich mal mit obiger Anmerkung von Paul mit einer eigenen Frage hierzu dran. Bei meinen Aktivitäten mit dem HTC unter CPM habe ich das Problem, das ein "Hello World" regelmäßig ein 14K Binary erzeugt, egal was ich versuche. Es macht den Eindruck, als wenn per Default eine ganze Menge Zeugs standardmäßig mit eingebunden wird, obwohl sie eigentlich garnicht benutzt bzw. angefordert werden. Eben solche Sachen wie File-Operationen, Mathe-Funktion etc. Nur für die Ausgabe eines schnöden einzeiligen Textes ist das alles sicherlich nicht erforderlich. Beim Aufruf des C309 vom HTC-Paket startet anscheined ein Batch-Prozessor, der vordefiniert alle erforderlichen Schritte für die Übersetzung nacheinander abarbeitet. Beim zcc dürfte das nicht viel anders sein, wie es scheint. Dieser Batch-Prozess nimmt durchaus zusätzliche Parameter entgegen, aber anscheinend nicht so, das sich damit ein Ausschluß von unerwünschten Dingen im fertigen Binary erreichen läßt. Ich habe Dr. Google einmal hierzu bemüht und bin auf Hinweise gestoßen, das da ev. im C-Standard Papier (hoffe mal, ich formuliere das richtig) Vorgaben definiert sind, wie automatische Compilierung oder explizierte befehlszeilengesteuerte Übersetzung zu behandeln sind. Wenn ich also jeden Schritt einzeln anstoße, kann ich mehr Paramter angeben, die dann wohl auch beachtet werden. Mithin ist eine bessere Beeinflussung des Ergebnis (speicheroptimiert oder laufzeitoptimiert...) möglich.

Ist dazu etwas bekannt ?
Was der HTC so tut, weiß ich nicht. Ich kenne den Compiler nicht. Der zcc tut so einiges, darunter Compiler-Aufruf, Linker-Aufruf, Assembler-Aufruf, Optimizer-Aufruf, Disk-Image-Erzeugung, usw. Leider ist der zcc nicht ausführlich dokumentiert. Wenn man ganz genau wissen will, was er tut, dann muss man wohl in den Source Code des zcc schauen...
Je nach Compiler (und Linker) gibt es unterschiedliche Optionen. Was in allen C-Implementierungen gleich ist: zuerst wird der C-Präpozessor ausgeführt (die Präprozessor-Direktiven sind die Zeilen, die mit einem "#" beginnen), dann erst der eigentliche Compiler. Wie der dann den Code erzeugt, ist seine Sache. Viele C-Compiler - so auch die beiden vom z88dk unterstützten - erzeugen Assembler-Code und nicht direkt Maschinencode. D.h. nach dem Compile-Vorgang wird noch ein Assembler aufgerufen um das fertige Binary zu erhalten, welches schließlich vom Linker in eine ausführbare COM-Datei überführt wird. Und schlussendlich wird noch ein Disk-Image erzeugt, das die COM-Datei enthält.
von bbock
19.03.2023, 11:01
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 505270

Re: Fragen und Antworten zum C-Kurs

Paul hat geschrieben: 19.03.2023, 08:43 ... Ich dachte wenn ich etwas "neues" hinzu nehmen möchte füge ich das mit einem include hinzu.
Das include fügt eine Header-Datei (*.h) in den Source Code ein. Damit werden Typen, Variablen und Funktionen deklariert. Das heißt, deren Namen werden bekannt gemacht. Zu den Namen braucht man aber auch noch den dazugehörigen Programmcode. Der kommt aus einer .c-Datei oder - bereits vorkompiliert - aus einer library.
Nehmen wir mal an, du hast per include "xyz.h" eine Funktion namens mySpecialFunction in deinem C-Programm verfügbar gemacht. Dann brauchst du zusätzlich entweder die xyz.c in deiner zcc-Source-Code-Liste oder du musst mit dem Linker eine library einbinden, die die Funktion mySpecialFunction enthält. Das geschieht im zcc-Aufruf über eine -l Option. zcc wird immer als Compiler-Frontend bezeichnet, aber eigentlich ruft zcc sowohl den C-Compiler als auch den Linker auf.
Paul hat geschrieben: 19.03.2023, 08:43 Auch das ich etwas vom linken explizit weglassen muss (Dateioperationen) verwirrt.
Vielleicht bin ich da etwas zu verwöhnt, ich kenne das eigentlich so das der Optimizer das selber erkennt.
...
Das mit dem Weglassen ist in der Tat etwas gewöhnungsbedürftig. Die Dateioperationen sind eben standardmäßig mit dabei. Die Option -lndos ist schon ein gewisser Logik-Bruch; hier wird keine Library dazugebunden, sondern etwas von einer Standard-Library weggelassen. :roll:
Den Optimizer betreffend können wir froh sein, dass es überhaupt einen gibt. Und ja: du bist verwöhnt! :P
von bbock
18.03.2023, 22:34
Forum: Hardware
Thema: Wir bauen einen Retro-JOYCE
Antworten: 11
Zugriffe: 65240

Re: Wir bauen einen Retro-JOYCE

Wir haben bereits in Helmarshausen einige Eckdaten besprochen, wie die "Retro-JOYCE" aussehen sollte. Da bereits über eine Reihe von Hardware-Details diskutiert wird, möchte ich mal auflisten, was mir wichtig wäre, damit man das nicht aus den Augen verliert. Also so etwas wie eine Grobspezifikation:
  1. Alle Teile sollten aus aktuell verfügbarer Hardware bestehen; es soll also keine echte JOYCE "ausgeschlachtet" werden. Ausnahme: 3"-Diskettenlaufwerke
  2. Kompaktes Gehäuse (darf gern ästhetisch ansprechend sein)
  3. Tastatur: USB oder PS/2, Originaltastatur anschließbar
  4. Laufwerke: Gotek oder HxC-Floppy-Emulator, 3"- oder 3,5"-Laufwerke anschließbar
  5. Monitor: VGA und/oder Video-Ausgang für einen monochromen Monitor
  6. Drucker: wäre schön, wenn man den Original-Drucker anschließen könnte