Die Suche ergab 233 Treffer

von bbock
24.03.2023, 14:07
Forum: Programmierung
Thema: Programmieren in C mit dem z88dk
Antworten: 20
Zugriffe: 9467

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: 2536

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) 2536 mal betrachtet
fnplot1.png
fnplot1.png (12.31 KiB) 2536 mal betrachtet
von bbock
19.03.2023, 11:11
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 33932

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: 33932

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: 5713

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
von bbock
18.03.2023, 21:18
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 33932

Re: Fragen und Antworten zum C-Kurs

Paul hat geschrieben: 18.03.2023, 17:41...
Was mache ich falsch?
Du hast die Mathematik-Library nicht eingebunden. Ändere deinen Compiler-Aufruf in:

zcc +cpm -subtype=pcw80 -lm -create-app calc.c -o calc.com

Damit sollte es funktionieren. Beschrieben ist das in Kapitel 5. Vielleicht sollte ich bei jedem Beispiel den zcc-Aufruf angeben, damit es keine Missverständnisse gibt. Zu den zcc-Parametern hatte ich sowieso noch einen Artikel geplant. Die Parameter sind nicht wirklich intuitiv, und manchmal auch etwas merkwürdig. Z.B. braucht man bei der Joyce (Platform PCW) die Option -create-app, wenn man etwas mit Grafik machen möchte, wodurch man auch ein Disketten-Image erstellt, welches man aber gar nicht unbedingt benötigt. Bei anderen Plattformen braucht man das nicht...

Das floatpack ist ebenfalls in der Mathe-Lib enthalten; ändere deinen zcc-Aufruf entsprechend.
von bbock
17.03.2023, 21:49
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 33932

Re: Fragen und Antworten zum C-Kurs

schombi hat geschrieben: 17.03.2023, 06:46 ...
Mal sehen, wie sich ein eher unterdurchschnittlicher Basicprogrammierer hier schlaegt :)
...
Das wird schon. Scheue dich nicht Fragen zu stellen, wenn du irgendwo nicht weiter kommst. Die Hauptsache ist, dass man am Ball bleibt. :)
von bbock
17.03.2023, 21:44
Forum: Programmierung
Thema: Programmieren in C mit dem z88dk
Antworten: 20
Zugriffe: 9467

13. Typ-Definitionen

Die einfachste Form der Typ-Definition in C ist die Umbenennung eines bestehenden Typs, wie z.B.

Code: Alles auswählen

typedef int LENGTH;
Das kann die Lesbarkeit fördern, indem man z.B. Variablen wie folgt definiert:

Code: Alles auswählen

LENGTH len, maxlen;
LENGTH *lengths[];
Oder man verwendet Abkürzungen wie

Code: Alles auswählen

typedef unsigned int UINT;
Auf unserem 8-Bitter hätte eine Variable vom Typ UINT dann einen Wertebereich von 0 bis 65535 - genau wie ein unsigned int, nur ist es mit dem typedef halt kürzer. Manch einer mag argumentieren, dass man damit nur die Sprache verwässert und Verwirrung stiftet. Es gibt natürlich auch sinnvollere Anwendungen von typedef, wie folgende Typvereinbarung für einen Knoten in einem binären Baum zeigt:

Code: Alles auswählen

typedef struct tnode {
    char *word;
    int count;
    struct tnode *left;
    struct tnode *right;
} TREENODE, *TREEPTR;
Hier wurden gleich zwei Namen festgelegt, TREENODE für die Struktur und TREEPRT für einen Zeiger auf einen TREENODE. Eine Knoten-Variable legt man z.B. folgendermaßen fest:

Code: Alles auswählen

TREENODE t;
Man hätte die Variable auch ohne typedef als struct tnode t; anlegen können, aber es ist durchaus angenehm, dass das Schlüsselwort struct bei Verwendung von typedef entfällt. Schauen wir uns an, wie das Programm aus Kapitel 12 bei Verwendung von typedef aussieht - wir speichern es als struct2.c:

Code: Alles auswählen

#include <stdio.h>
#include <string.h>

// A book.
typedef struct {
    char title[50];
    char author[50];
    char subject[100];
    int  book_id;
} Book, *BookPtr;

/* Print a book.
   Parameter: book  pointer to the book to print
*/
void printBook(BookPtr book) {
    printf( "title   : %s\n", book->title);
    printf( "author  : %s\n", book->author);
    printf( "subject : %s\n", book->subject);
    printf( "book_id : %d\n", book->book_id);
}

/* Main.
*/
int main(void) {
    Book book1;
    Book book2;

    /* book 1 specification */
    strcpy(book1.title, "Programmieren in C");
    strcpy(book1.author, "Kernighan & Ritchie"); 
    strcpy(book1.subject, "Programmierlehrbuch");
    book1.book_id = 5407;

    /* book 2 specification */
    strcpy(book2.title, "Telecom Billing");
    strcpy(book2.author, "Zara Ali");
    strcpy(book2.subject, "Telecom Billing Tutorial");
    book2.book_id = 5700;
    
    puts("*** Book 1 ***");
    printBook(&book1);
    
    puts("\n*** Book 2 ***");
    printBook(&book2);
    
    return 0;
}
Hier wurde auch gleich ein Pointer auf ein Book definiert, so dass die Funktion für die Ausgabe eines Buchs mit void printBook(BookPtr book) beginnt. Ohne den Pointer-Typ hätte man auch void printBook(Book *book) schreiben können.

Das Programm kompilieren wir zur Abwechslung mit

Code: Alles auswählen

zcc +cpm -subtype=pcw80 -lndos -create-app struct2.c -o struct2.com
Wir kennen bereits das Compiler-Frontend zcc mit den Optionen +cpm, -subtype=pcw80 und -create-app für die Schneider Joyce. Die Option -lndos sorgt für eine kleinere ausführbare com-Datei, weil der Code für Dateizugriffsfunktionen weggelassen wird. Das können wir hier tun, weil wir keine Dateioperationen verwenden.
von bbock
12.03.2023, 21:42
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 33932

Re: Fragen und Antworten zum C-Kurs

kurt hat geschrieben: 12.03.2023, 10:26 Eine Frage zu den Aufzählungstype und der Art wie TRUE u. FALSE als logisches Flag erzeugt werden. Man sieht auch häufig die Zu.-Fuß-Methode:

Code: Alles auswählen

TRUE  = 0;
FALSE = ~TRUE;
Ich nehme mal an, daß das persönlicher Programmierstil ist. Mir würde dieser Weg auch mehr zusprechen, da der logische Zusammenhang klarer ausformuliert ist (bin halt mehr Hardware-Fritze, FALSE ist nun mal das inverse von TRUE).
In C gibt es einen Datentyp bool erst ab C99. Er ist in stdbool.h als Makro definiert; der eigentliche Datentyp heißt _Bool. Die boole'schen Werte true und false (wohlgemerkt klein geschrieben) sind in derselben Header-Datei definiert. Vor C99 kann man prinzipiell nach Gusto vorgehen. false oder FALSE werden üblicherweise als 0 definiert, true oder TRUE als 1 oder -1 - Hauptsache ungleich 0. Deine Variante ist ausgesprochen unüblich. Eher würde man FALSE = 0 und TRUE = ~FALSE definieren. Damit wäre TRUE die bitweise Negation von 0, was einer -1 gleichkommt.
kurt hat geschrieben: 12.03.2023, 10:26 Im Kapitel Strukturen bein ersten Code-Beispiel steht:

Code: Alles auswählen

struct struct Book {
Da ist sicherlich ein "struct" zu viel. Gemeint ist sicherlich:

Code: Alles auswählen

struct Book {
denn sonst würde "struct" als Struktur "Book" definiert werden, was sicherlich nicht beabsichtigt ist (wie im 2ten Code-Beispiel gezeigt).
Danke für den Hinweis; ich habe es korrigiert.
kurt hat geschrieben: 12.03.2023, 10:26 Ich habe im 3ten Code-Beispiel zur Buch-Struktur einmal den ersten Text-String verdreifacht. Der HT-C Compiler meckert jedenfalls nicht, wenn die zuzuweisende (statische) Zeichenkette länger ist wie der dafür resevierte Speicher. Ist das generell so, das vom Compiler hier nichts kommt, obwohl er das erkennen könnte ? ist im Grunde kein Beinbruch, ist sicher besser Eingabetexte auf max. Länge zu kontrollieren, aber bei statische Sachen sollte der Compiler aufmucken (also gewissenmaßen Copy-und-Paste Fehler abfangen, denn statische Zeichenketten zählt man selten nach).
In C wird bei der Array-Indizierung keine Prüfung durchgeführt - weder beim Kompilieren noch zur Laufzeit. Die Verantwortung liegt hier beim Programmierer, was zu einer häufigen Fehlerquelle führt. Pascal prüft standardmäßig die Indexgrenzen, was aber zu Lasten der Performance geht (deshalb kann man die Prüfung auch per Compiler-Schalter deaktivieren). Es sei noch darauf hingewiesen, dass es in string.h neben strcpy auch die Funktion strncpy gibt, die über einen zusätzlichen Parameter eine Begrenzung der Anzahl kopierter Zeichen sicherstellt. Sie ist insbesondere dann wichtig, wenn man nicht sicherstellen kann, dass der zu kopierende String die Länge des Ziel-Arrays nicht überschreitet. Beim Kopieren von String-Konstanten benutzt man aus Effizienzgründen lieber strcpy.
von bbock
09.03.2023, 15:18
Forum: Programmierung
Thema: Fragen und Antworten zum C-Kurs
Antworten: 108
Zugriffe: 33932

Re: Fragen und Antworten zum C-Kurs

Hallo Paul,
ich wünsche dir gute Besserung! Schade, das wir uns dieses Wochenende nicht sehen werden.