Fragen und Antworten zum C-Kurs

Software-Entwicklung, Compiler, Interpreter, ...
Paul
Beiträge: 145
Registriert: 17.09.2017, 22:27
Wohnort: Germanys west end

Re: Fragen und Antworten zum C-Kurs

Beitrag von Paul »

Sorry, ich hinke etwas hinterher aber jetzt ist ja Wochenende ich bemühe mich aufzuholen.
Du schreibst das jede Anweisung mit einem ; beendet wird.
Mehrere Anweisungen umschließt man mit { }.
Jetzt frage ich mich ob C das innerhalb der Klammern als eine Anweisung sieht und warum dann nach der "Klammer zu" kein Semikolon steht.
Ach ja, ich habe heute nochmal HelloGFX gestartet, da ist tatsächlich ein Punkt mitten im Kreis, das war gar kein Staubkorn :mrgreen:
Paul
Beiträge: 145
Registriert: 17.09.2017, 22:27
Wohnort: Germanys west end

Re: Fragen und Antworten zum C-Kurs

Beitrag von Paul »

So, prim.c läuft ebenfalls.
Dabei hatte ich meinen ersten Tippfehler - Printf statt printf ;)
und windows teilte mir mit das es sich nicht in der lage sieht prim.com auszuführen :(

ich darf anscheinend nicht *a + 4 = 42; schreiben. Der Compiler meckert das 4 kein LValue sei. Wie müsste ich das schreiben damit 4 ein LValue ist?
kurt
Beiträge: 188
Registriert: 26.10.2019, 20:11

Re: Fragen und Antworten zum C-Kurs

Beitrag von kurt »

Moin Bernd,
die Assembler-Codesequenzen sind ein sehr interessanter Einblick in die Art wie die Compiler den C-Code umsetzen. Wenn ich die beiden Assembler-Ergebnisse einmal genauer betrachte, dann erscheint mir das Ergebnis, welches der sccz80 produziert, näher an den Vorgaben des C-Codes zu sein, ganz im Gegensatz zum zsdcc. Der sccz80 legt den Zeiger auf den Ausgabetext auf den Stack, gibt den Text aus und räumt anschließend durch pop bc den gesicherten Zeiger wieder ab. Dann gibt es ein LD hl,0 für das RETURN 0, ganz wie es im C-code steht. Der zsdcc lädt nach dem call _printf anscheinend ein Flag von _printf ins CPU Statusregister - eine Optimierung ?. Wie's dann weitergeht, ist wegen der Endlosschleife leider nicht zu sehen, aber diese Vorgehensweise wirkt auf mich wie ein unsauberes Vorgehen. So gesehen, würde ich mich eher für den sccz80 als Compiler entscheiden. ;)

Aus rein verständnisstechnischer Sicht, würde ich trotzdem die 'while (true) {....} Schleife bevorzugen, Je früher ersichtlich wird, was beabsichtigt ist, umso besser. C hat ohnehin einen gewissen Hang zum 'Abküfi' ... ('Abküfi' => Abkürzungsfimmel) :)

Off-Topic: Ich versuche mich mit den Beispielen, wenn möglich, auf drei Systemen: PC, Multicomp und die Joyce. Aber jedesmal, wenn die Joyce dran ist, habe ich das Gefühl, mir sitzt Prinz Walium gegenüber. Geht es nur mir oder Euch auch so ? Wie hat man das 'Damals' nur ausgehalten. Da scheint sich doch eine Zeitenwende abgespielt zu haben... :lol:
kurt
Beiträge: 188
Registriert: 26.10.2019, 20:11

Re: Fragen und Antworten zum C-Kurs

Beitrag von kurt »

>>Wie müsste ich das schreiben damit 4 ein LValue ist?
Das was Du vrsuchst ist Pointer-Arithmetik, das muß dem Compiler aber klar gemacht werden, sonst versteht er es falsch. Versuch einmal soetwas, müßte gehen: *(&a + 4) = 42;. '&a' greift auf den Inhalt von a zu, addiert 4 hinzu und benutzt das Ergebnis dann, um 42 auf die Stelle zu schreiben, auf die *a zeigt. Das ist genau das, was ich an C so liebe. ;)
Paul
Beiträge: 145
Registriert: 17.09.2017, 22:27
Wohnort: Germanys west end

Re: Fragen und Antworten zum C-Kurs

Beitrag von Paul »

Ich wollte auf die Adresse a +4, also a[2] zugreifen, also *(a+2) aber ohne die Klammer.

Ginge eventuell

Code: Alles auswählen

a += 4;
*a = 42;
a -=4;
:?:

Ich würde es selbst ausprobieren aber ich versuche gerade die Scharniere meines Notebooks zu "reparieren"
Zuletzt geändert von Paul am 25.02.2023, 12:56, insgesamt 3-mal geändert.
Paul
Beiträge: 145
Registriert: 17.09.2017, 22:27
Wohnort: Germanys west end

Re: Fragen und Antworten zum C-Kurs

Beitrag von Paul »

Davon abgesehen, darf ich mir etwas wünschen?
Ich möchte in einem der nächsten Beispiele gerne
aus Basic

Code: Alles auswählen

10 PRINT AT(10,14);"O"; 
wissen wie es in C aussieht
Schönes Wochenende
Benutzeravatar
bbock
Beiträge: 247
Registriert: 08.02.2015, 15:31

Re: Fragen und Antworten zum C-Kurs

Beitrag von bbock »

Zur Pointerarithmetik:
Wenn du auf ein einzelnes Byte zugreifen möchtest, dann solltest du einen char Pointer verwenden. Sagen wir mal, du hast schon einen int Pointer bzw. einen int Array a, wie im Beispiel in 10.2. Dann könntest du folgendes machen:

char *cp;
cp = (char *) a;
*(cp + 4) = 42;

Oder - ohne separate Pointer-Variable:

*( (char *) a + 4) = 42;

Man nennt das type casting; das hatten wir noch nicht...
Sagen wir, a liegt an der Speicheradresse 3000 und der Array ist mit Nullen initialisiert. Dann sieht das im Speicher so aus:
a[0] - 3000: 0 0
a[1] - 3002: 0 0
a[2] - 3004: 0 0
a[3] - 3006: 0 0
a[4] - 3008: 0 0

( (char *) a + 4) ist dann 3004, durch *( (char *) a + 4) = 42; änderst du das erste Byte des dritten int-Werts, also des int-Werts mit dem Index 2. Das ist das LSB (least significant byte), weil der Z80 int-Werte im little endian Format verarbeitet. Ein printf("%d", a[2]); liefert dann 42, denn das MSB (most significant Byte) ist 0.
a[0] - 3000: 0 0
a[1] - 3002: 0 0
a[2] - 3004: 42 0
a[3] - 3006: 0 0
a[4] - 3008: 0 0
Paul
Beiträge: 145
Registriert: 17.09.2017, 22:27
Wohnort: Germanys west end

Re: Fragen und Antworten zum C-Kurs

Beitrag von Paul »

Vielen Dank!
Benutzeravatar
bbock
Beiträge: 247
Registriert: 08.02.2015, 15:31

Re: Fragen und Antworten zum C-Kurs

Beitrag von bbock »

Paul hat geschrieben: 25.02.2023, 12:51 Davon abgesehen, darf ich mir etwas wünschen?
Ich möchte in einem der nächsten Beispiele gerne
aus Basic

Code: Alles auswählen

10 PRINT AT(10,14);"O"; 
wissen wie es in C aussieht
Schönes Wochenende
Das würde man in C ähnlich wie in TurboPascal mit gotoxy(10, 14); machen - normalerweise...

In der Theorie muss man dazu conio.h einbinden:

Code: Alles auswählen

#include <stdio.h>
#include <conio.h>

int main(void) {
    gotoxy(10, 14);
    putchar('O'); // oder printf("%s", "O");
}
In der Praxis funktioniert das aber nicht, weil das z88dk das leider bei der Plattform Amstrad PCW nicht unterstützt. Ich habe das so gelöst, dass ich meine eigene Funktion gotoXY geschrieben habe (mit XY in Großbuchstaben, damit es keine Namenskonflikte mit gotoxy aus conio.h gibt):

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
}

int main(void) {
    gotoXY(10, 14);
    putchar('O'); // oder printf("%s", "O");
}
Benutzeravatar
bbock
Beiträge: 247
Registriert: 08.02.2015, 15:31

Re: Fragen und Antworten zum C-Kurs

Beitrag von bbock »

kurt hat geschrieben: 25.02.2023, 12:33 ...Versuch einmal soetwas, müßte gehen: *(&a + 4) = 42;. '&a' greift auf den Inhalt von a zu, addiert 4 hinzu und benutzt das Ergebnis dann, um 42 auf die Stelle zu schreiben, auf die *a zeigt. ...
Nein, a ist ja schon ein Pointer; &a ist die Adresse der Pointer-Variablen, das ist ein Schritt zu weit zurück. *(a + 4) = 42; wäre richtig, wenn a ein char-Pointer wäre. Weil's aber ein int-Pointer ist, müssen wir dem C-Compiler sagen, dass er a wie einen char-Pointer behandeln soll - via type cast:
*( (char *)a + 4) = 42;
  1. (char *)a wandelt den int-Pointer in einen char-Pointer um.
  2. + 4 addiert 4 zur Speicheradresse dazu (jetzt wirklich 4 Bytes und nicht 4 int-Werte respektive 8 Bytes)
  3. *(...) dereferenziert den Pointer, d.h. wir kommen von der Adresse zum darunter gespeicherten Wert. Das ist ein einzelnes Byte, weil wir ja einen char-Pointer dereferenzieren.
  4. = 42 speichert den Wert 42 als einzelnes Byte an der neu berechneten Speicheradresse
Antworten