Sie sind nicht angemeldet.

Toshi

Vereinsmitglied

  • »Toshi« ist männlich
  • »Toshi« ist der Autor dieses Themas

Beiträge: 3 359

Wohnort: Oedheim/BaWü

Lieblingscomputer: Sage II

  • Nachricht senden

1

Dienstag, 12. September 2017, 22:36

Banner in C

Hallo!

Ich versuche mich ein wenig in C einzulesen, und wollte dann das Unix-C Banner Programm auf die Sage bringen und vertsehen, warum es tut, was es tut.

Vielleicht mag mir jemand die Hauptschleife erklären? Das Programm ist zwar kurz, aber für mich nicht a priori ersichtlich.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*****************************************************************
 *
 * SYSVbanner.c
 *
 * This is a PD version of the SYS V banner program (at least I think
 * it is compatible to SYS V) which I wrote to use with the clock
 * program written by:
 **     DCF, Inc.
 **     14623 North 49th Place
 **     Scottsdale, AZ 85254
 * and published in the net comp.sources.misc newsgroup in early July
 * since the BSD banner program works quite differently.
 *
 * There is no copyright or responsibility accepted for the use
 * of this software.
 *
 * Brian Wallis, brw@jim.odr.oz, 4 July 1988
 *
 *****************************************************************/

/* Changes by David Frey, david@eos.lugs.ch, 3 February 1997:
 * 1. protoized and indented, 2. changed @ character to #
 */

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

char *glyphs[] =
{
  "         ###  ### ###  # #   ##### ###   #  ##     ###  ",
  "         ###  ### ###  # #  #  #  ## #  #  #  #    ###   ",
  "         ###   #   # ########  #   ### #    ##      #   ",
  "          #            # #   #####    #    ###     #    ",
  "                     #######   #  #  # ####   # #       ",
  "         ###           # #  #  #  # #  # ##    #        ",
  "         ###           # #   ##### #   ### #### #       ",

  "   ##    ##                                            #",
  "  #        #   #   #    #                             # ",
  " #          #   # #     #                            #  ",
  " #          # ### ### #####   ###   #####           #   ",
  " #          #   # #     #     ###           ###    #    ",
  "  #        #   #   #    #      #            ###   #     ",
  "   ##    ##                   #             ###  #      ",

  "  ###     #    #####  ##### #      ####### ##### #######",
  " #   #   ##   #     ##     ##    # #      #     ##    # ",
  "# #   # # #         #      ##    # #      #          #  ",
  "#  #  #   #    #####  ##### ####### ##### ######    #   ",
  "#   # #   #   #            #     #       ##     #  #    ",
  " #   #    #   #      #     #     # #     ##     #  #    ",
  "  ###   ##### ####### #####      #  #####  #####   #    ",

  " #####  #####    #     ###      #           #     ##### ",
  "#     ##     #  # #    ###     #             #   #     #",
  "#     ##     #   #            #     #####     #        #",
  " #####  ######         ###   #                 #     ## ",
  "#     #      #   #     ###    #     #####     #     #   ",
  "#     ##     #  # #     #      #             #          ",
  " #####  #####    #     #        #           #       #   ",

  " #####    #   ######  ##### ###### ############## ##### ",
  "#     #  # #  #     ##     ##     ##      #      #     #",
  "# ### # #   # #     ##      #     ##      #      #      ",
  "# # # ##     ####### #      #     ######  #####  #  ####",
  "# #### ########     ##      #     ##      #      #     #",
  "#     ##     ##     ##     ##     ##      #      #     #",
  " ##### #     #######  ##### ###### ########       ##### ",

  "#     #  ###        ##    # #      #     ##     ########",
  "#     #   #         ##   #  #      ##   ####    ##     #",
  "#     #   #         ##  #   #      # # # ## #   ##     #",
  "#######   #         ####    #      #  #  ##  #  ##     #",
  "#     #   #   #     ##  #   #      #     ##   # ##     #",
  "#     #   #   #     ##   #  #      #     ##    ###     #",
  "#     #  ###   ##### #    # ########     ##     ########",

  "######  ##### ######  ##### ########     ##     ##     #",
  "#     ##     ##     ##     #   #   #     ##     ##  #  #",
  "#     ##     ##     ##         #   #     ##     ##  #  #",
  "###### #     #######  #####    #   #     ##     ##  #  #",
  "#      #   # ##   #        #   #   #     # #   # #  #  #",
  "#      #    # #    # #     #   #   #     #  # #  #  #  #",
  "#       #### ##     # #####    #    #####    #    ## ## ",

  "#     ##     ######## ##### #       #####    #          ",
  " #   #  #   #      #  #      #          #   # #         ",
  "  # #    # #      #   #       #         #  #   #        ",
  "   #      #      #    #        #        #               ",
  "  # #     #     #     #         #       #               ",
  " #   #    #    #      #          #      #               ",
  "#     #   #   ####### #####       # #####        #######",

  "  ###                                                   ",
  "  ###     ##   #####   ####  #####  ###### ######  #### ",
  "   #     #  #  #    # #    # #    # #      #      #    #",
  "    #   #    # #####  #      #    # #####  #####  #     ",
  "        ###### #    # #      #    # #      #      #  ###",
  "        #    # #    # #    # #    # #      #      #    #",
  "        #    # #####   ####  #####  ###### #       #### ",

  "                                                        ",
  " #    #    #        # #    # #      #    # #    #  #### ",
  " #    #    #        # #   #  #      ##  ## ##   # #    #",
  " ######    #        # ####   #      # ## # # #  # #    #",
  " #    #    #        # #  #   #      #    # #  # # #    #",
  " #    #    #   #    # #   #  #      #    # #   ## #    #",
  " #    #    #    ####  #    # ###### #    # #    #  #### ",

  "                                                        ",
  " #####   ####  #####   ####   ##### #    # #    # #    #",
  " #    # #    # #    # #         #   #    # #    # #    #",
  " #    # #    # #    #  ####     #   #    # #    # #    #",
  " #####  #  # # #####       #    #   #    # #    # # ## #",
  " #      #   #  #   #  #    #    #   #    #  #  #  ##  ##",
  " #       ### # #    #  ####     #    ####    ##   #    #",

  "                       ###     #     ###   ##    # # # #",
  " #    #  #   # ###### #        #        # #  #  # # # # ",
  "  #  #    # #      #  #        #        #     ## # # # #",
  "   ##      #      #  ##                 ##        # # # ",
  "   ##      #     #    #        #        #        # # # #",
  "  #  #     #    #     #        #        #         # # # ",
  " #    #    #   ######  ###     #     ###         # # # #"};


int main(int argc, char **argv)
{
  int a, b, c, len, ind;
  char line[80];

  for (argv++; --argc; argv++) {
    len = strlen(*argv);
    if (len > 10)
      len = 10;
    for (a = 0; a < 7; a++) {
      for (b = 0; b < len; b++) {
	if ((ind = (*argv)[b] - ' ') < 0)
	  ind = 0;
	for (c = 0; c < 7; c++) {
	  line[b * 8 + c] = glyphs[(ind / 8 * 7) + a][(ind % 8 * 7) + c];
	}
	line[b * 8 + 7] = ' ';
      }
      for (b = len * 8 - 1; b >= 0; b--) {
	if (line[b] != ' ')
	  break;
	line[b] = '\0';
      }
      puts(line);
    }
    puts("");
  }
  return 0;
}


Vielen Dank.

Zumindest mein GCC unter Linux kompiliert das Programm anstandslos. Auf der Sage fehlt mir noch das "String.h". Da kann ich vermutlich ein beliebiges von einem anderen System nehmen, oder?
Gruß
Stephan
Link arms, don't make them

funkenzupfer

Z80 Versteher

  • »funkenzupfer« ist männlich

Beiträge: 690

Wohnort: in der Nähe von 51°04'27.3"N 6°28'02.3"E

Lieblingscomputer: Video Genie System EG3003

  • Nachricht senden

2

Dienstag, 12. September 2017, 22:56

Du meinst die Zeile

Quellcode

1
for (argv++; --argc; argv++) {
?
argc ist eine int Variable, die die Anzahl der Argumente in der Kommandozeile enthält.
Mit argv kannste mal eben 2 DIN A4 Aeiten voll schreiben.

Auf die Schnelle:
Programmaufruf:
banner Bla1 Test2 Murks3
Dann wird Bla1, Test2, Murks3 in der for (...) verarbeitet. Der jeweilieg String steht in *argv.
Was in der for(...) genau passiert, hab ich jetzt nicht geschaut, aber war auch glaube ich nicht deine Frage.

Alle Klarheiten beseitigt?

Eine meiner ersten Begegnung mit C war ein Listing fuer den Atari.

Quellcode

1
if (*++*++argv == 'c') {

Dahinter stand ein Kommentar (sinngemäß): Wer das nicht versteht, soll erstmal C lernen!

Also weisst du was du zu tun hast. :)

Viel Erfolg
;------------------------------------
;----- ENABLE NMI INTERRUPTS
(aus: IBM BIOS Source Listing)

3

Dienstag, 12. September 2017, 23:00

Das Programm scheint die Eingabe auf der Kommandozeile einfach in gross auszugeben?

Die äusserte Schleife a sind die Zeilen? Die Schleife b dann die Zeichen in der Zeile? Und c dann die Pixel von der Buchstabentzeile?

Von string.h scheinst Du ja nur strlen zu brauchen? Das kannst Dir zu not ja auch schnell selbst schreiben?

int strlen( char *c) {
int len = 0;
while( *c++ != 0) {
++len;
}

return len;
}

, oder so ähnlich.

ChaosRom

Fortgeschrittener

  • »ChaosRom« ist männlich

Beiträge: 404

Wohnort: Ditzingen

Lieblingscomputer: Ich rück keinen mehr raus!

  • Nachricht senden

4

Mittwoch, 13. September 2017, 09:09

int strlen( char *c) {
int len = 0;
while( *c++ != 0) {
++len;
}
return len;
}

Wobei der eingefleischte C-Hacker natürlich

Quellcode

1
while(*c++)

schreiben würde, "0" als "false" und "!=0" (ungleich null) als "true" interpretiert wird.
Das ist wahrscheinlich auch das Problem beim Verstehen von fremdem C-Code, dass
man in C viele Sachen sehr "kompakt" schreiben kann.
Ein schönes Beispiel dafür ist die for-Schleife im Beispiel.
Ein for in C hat eigentlich die Form:

Quellcode

1
for(<Initialisierung>;<Vergleich>;<De-/Inkrement) <Anweisung>

Im Unterschied zu anderen Sprachen, kann man aber beliebiegen Code an allen
vier Stellen einsetzen.
Damit wird aus "for i:= 1 to 10 do <etwas>;" wird in C "for(i=1;i<=10;i++) <etwas>", wenn man
aber abwärts zählt kann man das in C noch anders machen
Aus "for i:= 10 down to 1 do <etwas>;" wird in C "for(i=11;--i;) <etwas>".
"--i" verringert i um 1 und verwendet das Ergebnis an der Stelle, die eigentlich der
Vergleich ist. Die Schleife bricht tatsächlich bei 1 ab, da i eben wieder erst verringert
wird und dann ausgewertet. i ist dann 0 also false und damit ist die Schleife zuende.
Wenn man C kann, ist das ganz logisch, kommt man aber von einer "strengeren"
Programmierschleife ist das schon etwas schwer verständlich und das ist noch ein
einfaches Beispiel. 8-)
Das Genie beherrscht das Chaos

5

Mittwoch, 13. September 2017, 09:52

In Variable a steht die Zeile des Banner-Buchstabenss, der aus 8 Zeilenen (0 to 7) besteht.
In b steht die Position des gerade bearbeiteten Buchstabens aus dem Übergabewert. Dabei ist zu beachten, dass übergebene Wörter, die mehr als 10 Zeichen haben, auf 10 Zeichen gekürzt werden! Da ein Großbuchstabe 7 Zeichen breit ist, und hinter jedem Großbuchstaben ein Leerzeichen als Lücke zum nächsten Großbuchstabens eingefügt wird ("line[b * 8 + 7] = ' ';"), ergibt sich daraus, dass maximal die volle Breite der Textzeile, 80 Zeichen, mit diesen maximal 10 Buchstaben gefüllt werden. So wird ein ungewollter Zeilenumbruch innerhalb des Banners verhindert.
Variable c ist das "Pixel" des Großbuchstabens aus der obigen "Data-Wüste", welche die Großbuchstaben enthält.
Variabe line beinhaltet die zusammengesetzte Zeile des Großbuchstabentextes, bestehend aus "#" und " ".

Die Hauptschleife holt nacheinander alle Übergabeparameter, z.B. alle Worte eines Satzes, in die innere Schleife. Es wird ein Wort nach dem anderen ausgegeben und wenn ein komplettes Wort ausgegeben wurde, wird eine neue Großbuchstabenzeile aufgemacht.
In der Schleife darin wird also Zeile für Zeile der Ausgabetext in Großbuchstaben zusammengesetzt, die Hauptschleife durchläuft Zeile für Zeile die Großbuchstaben und holt sich dabei die "Pixel" (also " " oder "#") für die aktuelle Zeichenposition im Parameter-Text. Der puts(line) Befehl jeweils die komplette Zeile aus.

Die untere Schleife mit dem Break macht nochmal was mit der zusammengesetzten Zeile bevor sie ausgegeben wird, scheinbar ersetzt sie die "#" durch "\0", was auch immer das für einen Sinn hat.
1ST1

Schroeder

Vereinsmitglied

Beiträge: 1 183

Wohnort: Haltern am See

Lieblingscomputer: Mein erster 286er von 1988, läuft immer noch.

  • Nachricht senden

6

Mittwoch, 13. September 2017, 10:50

Moin,

ich persönlich halte die Art der C Programmierung für höchst unnötig und ist eher ein auf "Dicke Hose machen".

Bei meiner Programmierung von Steuergeräten versuche ich den Code möglichst einfach und lesbar zu halten. Lieber nutze ich dedizierte Variablen als das ich alles in eine Zeile quetsche.
Meist ist der komplexe Code am Ende nicht wirklich schneller, im Gegenteil hängt es stark vom Compiler ab was daraus wird.

Klar macht es Spaß solche Anweisungen zu basteln...

Gruss,
Peter

funkenzupfer

Z80 Versteher

  • »funkenzupfer« ist männlich

Beiträge: 690

Wohnort: in der Nähe von 51°04'27.3"N 6°28'02.3"E

Lieblingscomputer: Video Genie System EG3003

  • Nachricht senden

7

Mittwoch, 13. September 2017, 11:01

Die untere Schleife mit dem Break macht nochmal was mit der zusammengesetzten Zeile bevor sie ausgegeben wird, scheinbar ersetzt sie die "#" durch "\0", was auch immer das für einen Sinn hat.

Es werden von hinten nach vorne alle Leerzeichen durch \0 ersetzt bis ein Zeichen ungleich Leerzeichen ist. Sonst hatte line[] kein \0-Ende, was meist sehr unschoen aussieht!
;------------------------------------
;----- ENABLE NMI INTERRUPTS
(aus: IBM BIOS Source Listing)

ChaosRom

Fortgeschrittener

  • »ChaosRom« ist männlich

Beiträge: 404

Wohnort: Ditzingen

Lieblingscomputer: Ich rück keinen mehr raus!

  • Nachricht senden

8

Mittwoch, 13. September 2017, 11:38

Bei meiner Programmierung von Steuergeräten versuche ich den Code möglichst einfach und lesbar zu halten. Lieber nutze ich dedizierte Variablen als das ich alles in eine Zeile quetsche.
Meist ist der komplexe Code am Ende nicht wirklich schneller, im Gegenteil hängt es stark vom Compiler ab was daraus wird.

Klar macht es Spaß solche Anweisungen zu basteln...

Da gebe ich dir vollkommen recht - bei beidem.
In meiner frühen Sturm und Drang Zeit des Programmieren, fand ich es cool möglichst kurzen und somit vermeindlich schnellen Code
zu schreiben. Doch wenn man dann mal nach einiger Zeit selbst eigenen Code erst aufwändig analysieren muss, um zu verstehen was
man da geschrieben hat, wird einem klar, dass Wartbarkeit ein durchaus wichtiger Aspekt von Code ist. Solche C-Frickeleien hab ich
immer als WOC = Write Only Code bezeichnet. Trotzdem finde ich es durchaus lehrreich, ich mit C zu beschäftigen. Momentan
programmieren die meisten um mich herum in C# und haben m.E. oft keine Ahnung über die Performance-Auswirkungen von den
komfortablen Mechanismen zur automatischen Speicherverwaltung.
Das Genie beherrscht das Chaos

Beiträge: 688

Wohnort: Dresden (nahebei)

Lieblingscomputer: Acorn RISC OS + +4

  • Nachricht senden

9

Mittwoch, 13. September 2017, 11:45

Ein for in C hat eigentlich die Form:

Quellcode

1
for(<Initialisierung>;<Vergleich>;<De-/Inkrement) <Anweisung>


Im Unterschied zu anderen Sprachen, kann man aber beliebiegen Code an allen
vier Stellen einsetzen.


ich persönlich halte die Art der C Programmierung für höchst unnötig und ist eher ein auf "Dicke Hose machen".


Besonders bemerkenswert find ich so Schleifen mit zwei oder mehr Variablen. Ist ganz extrem (un)übersichtlich und wenn man das noch nie gesehen hat vorher, denkt man, daß die einen veralbern wollen.

Das mit der dicken Hosen ist sicher manchmal durchaus so. Manchmal ist es aber auch wirklich einfacher, wenn man in dem Maschinendenkmodell drinsteckt, sowas so zu schreiben. Daß das am Ende - heutzutage - noch den eigentlichen Programmcode verbessert, glaube ich auch nicht. Es verschlechtert aber für alle nicht-C-Könner die Lesbarkeit ungemein - was ja wiederum für die Aufrechterhaltung des eigenen Coolnessfaktors unabdingbar ist.

Anscheinend hat aber bisher noch niemand das Geheimrezept gefunden, mit dem man "Programmierung für Alle" einführen kann. Python und Ruby, evtl. Lua u.ä. versuchen sowas zwar, aber zwischen dem Google-Scratch Ansatz und den Textlösungen klafft da irgendwie eine gewaltige Lücke. Rechenpower genug sollte mittlerweile ja da sein, daß das allgemein nutzbar wird. Das wirklich bemerkenswerte an Rechnern ist doch, daß die das machen, was man ihnen sagt, nur die Art der Vermittlung ist gewaltig barrierenbewehrt, immer noch.

ChaosRom

Fortgeschrittener

  • »ChaosRom« ist männlich

Beiträge: 404

Wohnort: Ditzingen

Lieblingscomputer: Ich rück keinen mehr raus!

  • Nachricht senden

10

Mittwoch, 13. September 2017, 12:00

Anscheinend hat aber bisher noch niemand das Geheimrezept gefunden, mit dem man "Programmierung für Alle" einführen kann. Python und Ruby, evtl. Lua u.ä. versuchen sowas zwar, aber zwischen dem Google-Scratch Ansatz und den Textlösungen klafft da irgendwie eine gewaltige Lücke. Rechenpower genug sollte mittlerweile ja da sein, daß das allgemein nutzbar wird. Das wirklich bemerkenswerte an Rechnern ist doch, daß die das machen, was man ihnen sagt, nur die Art der Vermittlung ist gewaltig barrierenbewehrt, immer noch.

Ich selbst hab zwar nie etwas mit Smalltalk gemacht, hab aber im Hinterkopf abgespeichert, dass das ein sehr konsequenter Ansatz in Richtung "einfache Mensch-Maschine-Schnittstelle" war.
In Wikipedia hab ich jetzt gerade nachgeschaut, dass Smalltalk mit Squeak gerade wieder eine Renaissance erlebt
https://de.wikipedia.org/wiki/Smalltalk_…mmiersprache%29
und
https://de.wikipedia.org/wiki/Squeak
Das Genie beherrscht das Chaos

Beiträge: 688

Wohnort: Dresden (nahebei)

Lieblingscomputer: Acorn RISC OS + +4

  • Nachricht senden

11

Mittwoch, 13. September 2017, 12:37

OK. Werd ich mal angucken. Lustige Maus als Symbol haben sie ja schonmal.
Smalltalk steht bei mir seit laaangem auf gleichen Liste wie Prolog - unbedingt mal bißchen Angucken; aber bisher nicht passiert.


Zum C-Code noch: Wenn da glyphs ganz oben als glyphs[] Array mit einer Dimension belegt wird, ist das ja noch verstehbar. Wo dann der "mindfuck" dazukommt ist unten in der wichtigsten Zeile "von das Ganze", wenn zum Auslesen das Feld als glyphs[][] wieder auftaucht und damit plötzlich Zeilen und Spalten hat

Quellcode

1
	  line[b * 8 + c] = glyphs[(ind / 8 * 7) + a][(ind % 8 * 7) + c];

und quasi nach Buchstaben geordnet abgefragt wird mit einem Index (ind) der sich i.P. direkt aus dem ASCII Code des Zeichens ergibt

Quellcode

1
2
	if ((ind = (*argv)[b] - ' ') < 0)
	  ind = 0;

und daher, wie gedacht, von 0 bis ( 128 -32 ) läuft. Auch die Konstruktion hier oben ist eigentlich total simpel, aber schon fast unleserlich, für BASIC Mannen ( mich eingeschlossen ). Da wird nämlcih erstmal innerhalb der Klammer dem ind ein Wert zugewiesen und danach wird dann ind mit <0 verglichen und auf 0 gesetzt, wenns kleiner war ( alle Steuercodes ). Daß ind jetzt den Wert hat geht dabei beim lesen fast unter.
Und ind wird danach zum Auslesen eines Array verwendet, wobei es dem C völlig egal ist, wie man sich das anschaut. Solche Array Konstrukte sind i.P. nur sowas wie eine Schreiberleichterung für den Programmierer. Sie haben aber für den Rechner nicht viel Bedeutung, weshalb man eben auch nachträglich die Art des Auslesen anders verwenden kann, als das Belegen. Man muß sich das einfach als eine lange Reihe von "#" und " " im Speicher vorstellen, wo man halbwegs geschickt wissen muß, an welcher Stelle man was auslesen will. Es gibt da auch keine Tests darauf, ob das Sinn macht oder zulässig ist, was man als glyph[][] beschreibt. Sollte eigentlich bei dem Programm aus testbar sein, wenn man einen Wert größer als das letzte Zeichen eingibt, also irgendwas mit ASCII >= 128. Da solltte dann durchaus was angezeigt werden, aber nix Sinnvolles mehr, weil da plötzlich aus dem Bereich hinter der glyphs[] Variablen ausgelesen wird. Wenn dort zufällig Paßworte liegen, ist das dann schon interessant ( OK. Unwahrscheinlich. ). Einfach mal probieren !

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »ThoralfAsmussen« (13. September 2017, 12:50)


Schroeder

Vereinsmitglied

Beiträge: 1 183

Wohnort: Haltern am See

Lieblingscomputer: Mein erster 286er von 1988, läuft immer noch.

  • Nachricht senden

12

Mittwoch, 13. September 2017, 13:05

Zitat

Zum C-Code noch: Wenn da glyphs ganz oben als glyphs[] Array mit einer Dimension belegt wird, ist das ja noch verstehbar. Wo dann der "mindfuck" dazukommt ist unten in der wichtigsten Zeile "von das Ganze", wenn zum Auslesen das Feld als glyphs[][] wieder auftaucht und damit plötzlich Zeilen und Spalten hat


Wobei es oben ja schon zweidimensional durch die Zuweisung deklariert wird *c[]={...} Pointer, Arrays, alles egal ... ;)

Ich habe bei meinen Zeichenausgaben häufiger mit solchen Konstrukten Ärger gehabt. Daher verwende ich gerne Typendeklarationen.

Einfaches Beispiel für verkettete Strukturen für eine Warnungsanzeige im Auto:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
typedef const struct{
	const char *small;
	const char *large;
} warningcontent;

struct warning{
	struct warning *next;
	warningcontent *content;
	char active;
	char display;
	char timer;
}*wbegin,*wpointer,*prevWarning,woelpressure,wairbag,wengine,woellevel,wcoolentlevel,wgen,wbreak,wbreaklever,wfluid,wgas,wfrost;

// 3=rot; 9=grau; 10=gelb
// Bitmap gross 90x90
// Bitmap klein 30*30

//Oeldruck
warningcontent woelpressurecontent={
	"#UT3,#FU1,9,#UI216,___,84,#UT2,#FU8,1,",
	"#FR3,8,3,#RE14,3,#RR215,10,84,230,#UI104,75,83,"
};


Gruss,
Peter

13

Mittwoch, 13. September 2017, 14:32

Moin,

ich persönlich halte die Art der C Programmierung für höchst unnötig und ist eher ein auf "Dicke Hose machen".

Bei meiner Programmierung von Steuergeräten versuche ich den Code möglichst einfach und lesbar zu halten. Lieber nutze ich dedizierte Variablen als das ich alles in eine Zeile quetsche.
Meist ist der komplexe Code am Ende nicht wirklich schneller, im Gegenteil hängt es stark vom Compiler ab was daraus wird.

Klar macht es Spaß solche Anweisungen zu basteln...

Gruss,
Peter

Auch ich stimme Dir zu. Der Code sollte für Menschen gut verständlich sein, ohne daß man beim Lesen lange über überkandidelte Ausdrücke grübeln muß. Für Optimierungen ist der Compiler zuständig. Kleine Abkürzungen wie if (x) statt if (x != 0) sind schon in Ordnung, aber beim Hantieren mit verschachtelten *,&,--,++ schießt man sich leicht selbst ins Bein, und wenn es dann nicht tut, wie es soll, verbrät man mehr Zeit mit Debuggen als mit Programmieren.

Als man noch um jedes Byte kämpfen mußte, weil Speicher knapp und teuer war, waren die Maßstäbe natürlich andere.

Gruß,
Markus

Toshi

Vereinsmitglied

  • »Toshi« ist männlich
  • »Toshi« ist der Autor dieses Themas

Beiträge: 3 359

Wohnort: Oedheim/BaWü

Lieblingscomputer: Sage II

  • Nachricht senden

14

Mittwoch, 13. September 2017, 19:41

Man seid ihr alle schlau. :anbet: Ich muss das erst mal lesen und verstehen, was ihr geschrieben habt.

Kann mir jemand erklären, was es mit den Sternchen auf sich hat? Also zB "char **argv"?

Sternchen haben doch irgendwas mit Zeigern zu tun, aber ich muß gestehen, daß mir das Konzept noch reichlich nebulös vorkommt.
Link arms, don't make them

funkenzupfer

Z80 Versteher

  • »funkenzupfer« ist männlich

Beiträge: 690

Wohnort: in der Nähe von 51°04'27.3"N 6°28'02.3"E

Lieblingscomputer: Video Genie System EG3003

  • Nachricht senden

15

Mittwoch, 13. September 2017, 20:00

char **argv

Du wolltest es so:

argv ist eine Variable, die auf eine Speicherstelle zeigt, deren Wert zeigt auf eine Speicherstelle, in dr ein char steht.
Alles klar?

Jetzt die Langform:
Deine Kommandozeile sieht so aus:
prog.exe Param1 Test2 Bla3

Daraus wird eine Zeigertabelle erzeugt:
0: Zeiger auf prog.exe
1: Zeiger auf Param1
2: Zeiger auf Test2
3: Zeiger auf Bla3

argv dann auf diese Tabelle.

Jetzt klar?

Wenn nicht, was bestimmt kein Mackel ist, schreibst du am besten mal ein kleines Programm und startest es im Debugger. Danach schaust du dir den Speicher in Ruhe an.

Viel Erfolg
;------------------------------------
;----- ENABLE NMI INTERRUPTS
(aus: IBM BIOS Source Listing)

Toshi

Vereinsmitglied

  • »Toshi« ist männlich
  • »Toshi« ist der Autor dieses Themas

Beiträge: 3 359

Wohnort: Oedheim/BaWü

Lieblingscomputer: Sage II

  • Nachricht senden

16

Mittwoch, 13. September 2017, 20:04



Jetzt klar?


Klarer.
Ich dachte, es handelt sich dabei ein array vom typ string. So würde es vmtl. in Pascal aussehen.

Was ist denn der Unterschied zwischen einem Stern und zwei führenden Sternen?
Link arms, don't make them

funkenzupfer

Z80 Versteher

  • »funkenzupfer« ist männlich

Beiträge: 690

Wohnort: in der Nähe von 51°04'27.3"N 6°28'02.3"E

Lieblingscomputer: Video Genie System EG3003

  • Nachricht senden

17

Mittwoch, 13. September 2017, 20:16

C kennt keinen String.
In C stehen alle Zeichen im Speicher hintereinander und \0 ist die Endekennung.

char c
c ist eine Variable vom Typ char (-128 .. +127)

char * cp
cp ist eine Variable, die als Inhalt einen Zeiger (Adresse) auf eine Speicherstelle enthält, die einen char enthaelt.

char ** cpp
cpp ist eine Variable, die als Inhalt einen Zeiger (Adresse) auf eine Speicherstelle enthält, die als Inhalt einen Zeiger (Adresse) auf eine Speicherstelle enthält, die einen char enthaelt.
;------------------------------------
;----- ENABLE NMI INTERRUPTS
(aus: IBM BIOS Source Listing)

Toshi

Vereinsmitglied

  • »Toshi« ist männlich
  • »Toshi« ist der Autor dieses Themas

Beiträge: 3 359

Wohnort: Oedheim/BaWü

Lieblingscomputer: Sage II

  • Nachricht senden

18

Mittwoch, 13. September 2017, 20:28


char ** cpp


C kennt keine Strings. Soso.

Das mit dem einen Stern ist mir noch klar. Also ist bei *c der Inhalt beispielsweise Adresse 100, und der "String" "Hallo" belegt die Adressen
100 = "H", 101="a", 102="l", 103="l", 104="o", 105="\0" ?

Aber die 2 Sterne?
Welchen Sinn macht ein Zeiger auf einen Zeiger? Ist das ein Äquivalent eines Array of String?

Danke!
Stephan
Link arms, don't make them

ZuseZ1

Kuh-Treiber

  • »ZuseZ1« ist männlich

Beiträge: 524

Wohnort: Leverkusen

Lieblingscomputer: Apple //e

  • Nachricht senden

19

Mittwoch, 13. September 2017, 20:45

Doppelpointer, auch verketteter Zeiger, wird u.a. bei mehrdimensionalen Arrays verwendet.
Hab ich in meiner C-Zeit nie verwendet (weil nicht verstanden)
"There is no reason for any individual to have a computer in his home." Ken Olson, president, chairmen and founder of Digital Equipment Corp, 1977

funkenzupfer

Z80 Versteher

  • »funkenzupfer« ist männlich

Beiträge: 690

Wohnort: in der Nähe von 51°04'27.3"N 6°28'02.3"E

Lieblingscomputer: Video Genie System EG3003

  • Nachricht senden

20

Mittwoch, 13. September 2017, 20:50

C kennt keine Strings. Soso.

Auf jeden Fall keinen Typ String, so wie z.B. in Pascal.

Auch in C wird "Hello World" als String bezeichnet, aber eigentlich liegen nur Werte (ASCIIs) im Speicher.

Probier mal aus:
printf("Hello World!" + 6);

Aber hier verweis ich auf Schroeders Post u.a. zur Lesbarkeit von Code und Spielerein mit diesem.
Also nur zum Verstaendnis machen!

Also ist bei *c der Inhalt beispielsweise Adresse 100

Jein!

c = 100, besser: c = (char *) 100
*c = 'H', nicht "H"!!!

"H" entspricht 'H', '0' und hat als Wert die Adresse von 'H'.

Mal ganz rudimentaer:
C ist eine maschinenunabhaengige Assemblersprache, die ohne GOTOs auskommt.
Assembler kennt auch keine Strings, nur Speicherstellen, char, integer und Pointer.
;------------------------------------
;----- ENABLE NMI INTERRUPTS
(aus: IBM BIOS Source Listing)

funkenzupfer

Z80 Versteher

  • »funkenzupfer« ist männlich

Beiträge: 690

Wohnort: in der Nähe von 51°04'27.3"N 6°28'02.3"E

Lieblingscomputer: Video Genie System EG3003

  • Nachricht senden

21

Mittwoch, 13. September 2017, 20:54

Hab ich in meiner C-Zeit nie verwendet (weil nicht verstanden)


Unterschreib ich dir sofort! ;)
Weil ein Doppelpointer nichts miit mehrdimensionalen Arrays zu tun hat.

Ein int array[10][20] ist und bleibt ein int* (Ist nicht ganz korrekt ausgedrueckt! Sorry)
Auch hier liegen nur 200 Werte im Speicher. Nur der Compiler benutzt die [20] um die richtige Speicherstelle zu adressieren.

Nachtrag:
Die Speicherstelle von array[2][5] ist das gleiche wie von array[2 * 20 + 5]
;------------------------------------
;----- ENABLE NMI INTERRUPTS
(aus: IBM BIOS Source Listing)

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »funkenzupfer« (13. September 2017, 21:09)


funkenzupfer

Z80 Versteher

  • »funkenzupfer« ist männlich

Beiträge: 690

Wohnort: in der Nähe von 51°04'27.3"N 6°28'02.3"E

Lieblingscomputer: Video Genie System EG3003

  • Nachricht senden

22

Mittwoch, 13. September 2017, 20:57

Aber die 2 Sterne?
Welchen Sinn macht ein Zeiger auf einen Zeiger? Ist das ein Äquivalent eines Array of String?

So direkt benutzt man sowas selten.
Meistens entsteht ein ** durch Zeiger-Tabellen, z.B. beim char ** argv.
;------------------------------------
;----- ENABLE NMI INTERRUPTS
(aus: IBM BIOS Source Listing)

Beiträge: 688

Wohnort: Dresden (nahebei)

Lieblingscomputer: Acorn RISC OS + +4

  • Nachricht senden

23

Mittwoch, 13. September 2017, 21:53

Wobei es oben ja schon zweidimensional durch die Zuweisung deklariert wird *c[]={...} Pointer, Arrays, alles egal ... ;)


Da wir ja nun doch da gelandet sind, kannst Du das evtl. noch kurz ausführen - warum zweidimensional, bzw. wie meintest Du das ?
(Bei mir war zweite Dimension die zweite Doppelklammer.)

Sternchen haben doch irgendwas mit Zeigern zu tun, aber ich muß gestehen, daß mir das Konzept noch reichlich nebulös vorkommt.

Du wolltest es so:


Au weia, gleich direkt die richtige Frage erwischt...


Das schlimme an dem Zeug ist, das kann man halbwegs kapiert haben, und wenn dann ein Vierteljahr vergangen ist und das nächste Basteln ansteht, kommen einem wieder tausend unverstandene Probleme dabei auf. Meist ist man selbst dran schuld, aber es braucht auch oft lang bis man kapiert hat warum eigentlich.


Zum Doppelpointer: Das kann sehr sinnvoll sein und jeder der Pascaldemos kennt, hat sowas i.P. schonmal gesehen. Dort werden z.B. X,Y Paare + Farbwerte o.ä.in einem Array abgelegt und man könnte jetzt mit X[] und i den Wert auslesen und plotten. Sollen die Sachen aber vor dem Plotten sortiert werden, kann es sinnvoll sein, nur für das Sortieren ein Extra Array anzulegen, in das man nur die "i" Werte reinschreibt - am Anfang als Extra[0] bis Extra[last]. Wenn man nun die Sortierroutine laufen läßt, tauscht man nur die Werte in der Extra[] Liste um und faßt die eigentlichen Daten gar nicht mehr an. X[],Y[],Farbe[] bleiben also dabei unangetastet. Der Vorteil es ist um miin. einen Faktor 3 schneller und trotzdem sortiert.

Wenn man das gleiche Spiel nun mit Strings machen will, hat man das Problem, daß die Strings ja unterschiedlich lang sein können. Wenn man Speiherplatz sparen will, legt man also die Buchstaben einzeln in den Speicher und merkt sich z.B. die jeweilige Länge oder man benutzt eine Endemarkierung. Das wäre das Modell wie es in C gemacht wird. Da klebt am Ende diese "\0" mit dran. Damit man den Speicherplatz, der ja nicht mehr wie bei einem Array an einer definierten Stelle liegt, wiederfindet, braucht man aber schon den ersten Zeiger - also
char * pointer
wenn man diese Strings jetzt sortieren will, kann man den kompletten Speicher einmal umsortieren. Oder man tauscht direkt diese Zeiger aus, dann verliert man aber die Zuordnung, wie es am Anfang gewesen ist ( Reset auf Normalanordnung ist dann schwierig ). Oder man führt eine Liste mit Zeigern, die auf die Zeiger zeigen, die auf die Wortanfänge, d.h. die Einzelstring, zeigen. Das ist dann dieses
char ** doppelpointer

War hoffentlich ein bißchen nachvollziehbar ?

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »ThoralfAsmussen« (13. September 2017, 22:13)


ktf

Lochmacher

  • »ktf« ist männlich

Beiträge: 407

Wohnort: Düsseldorf

Lieblingscomputer: Apple //e & OKI IF-800 Model 30

  • Nachricht senden

24

Mittwoch, 13. September 2017, 22:44

Hehe, lustiger Thread.

Nur kurz zu dem Doppelpointer, da ich am Tablet tippere und es da schon blöd ist Code zu tippern:

Früher zur Kerninghan-Richie-C Zeit hat man argv (und envp) tatsächlich gerne als **argv deklariert.

Im Speicher ist argv als NULL-terminiertes Pointer-Array abgelegt. Das meint: argv ist ein Array aus Pointern. Enthält einer der Pointer den Wert NULL, ist das Array zuende. Die einzelnen Pointer zeigen auf Strings, die die einzelnen Argumente enthalten.

Mit ANSI-C wird das heutzutage daher so deklariert: char *argv[ ];

Wenn der Compiler und das OS korrekt arbeiten, machen folgende beiden Codeabschnitte das selbe (Programmname und alle Argumente ausgeben):

Quellcode

1
2
3
4
5
int i;
for (i = 0; i <= argc; i++) puts(argv[i]);

char **p;
for (p = argv; *p != NULL; p++) puts(*p);

Der zweite Fall ist für den Laien natürlich etwas schwieriger zu verstehen, hat aber den Vorteil, dass keinerlei Index-Offsets errechnet werden müssen, was bei großen Datenmengen oder langen Schleifen schon merkbar ins Gewicht fallen kann.

Ansonsten kann ich nur zustimmen: Lieber leserlichen Code, als extrem gepackte Konstrukte. Erst wenn die Laufzeitanalyse zeigt, dass man dringend optimieren muss, sollte man tiefer in die Trickkiste greifen. Aber dann bitte mit einem verständlichen Kommentar.

Was allerdings unleserlich ist, hängt natürlich auch vom Background des Lesenden ab. Ich selbst finde z.B. Stringbearbeitung mit Pointern verständlicher und eleganter, als manch Riesenausdruck mit tief geschachtelten LEN und MID Ausdrücken im Index bei BASIC. ;)

-- Klaus

EDIT: Natürlich ein paar Sternchen vergessen ^^
[ ... to boldly code where no byte has gone before ... ]

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »ktf« (13. September 2017, 23:04)


25

Donnerstag, 14. September 2017, 03:42

Macht aber schon Sinn, dass sie jetzt in C++ so nach und nach die Java string Klasse nach programmieren. Einige wichtige Dinge wie trim, endsWith usw fehlen ja immer noch.

ChaosRom

Fortgeschrittener

  • »ChaosRom« ist männlich

Beiträge: 404

Wohnort: Ditzingen

Lieblingscomputer: Ich rück keinen mehr raus!

  • Nachricht senden

26

Donnerstag, 14. September 2017, 08:43

Daraus wird eine Zeigertabelle erzeugt:
0: Zeiger auf prog.exe
1: Zeiger auf Param1
2: Zeiger auf Test2
3: Zeiger auf Bla3

Das erklärt auch die Zeile 132 des Codes: for(argv++ ...
Damit zeigt der Zeiger schon im ersten Schleifendurchlauf auf das zweite "Array"-Element, nämlich den ersten Parameter.
Das Genie beherrscht das Chaos

Beiträge: 688

Wohnort: Dresden (nahebei)

Lieblingscomputer: Acorn RISC OS + +4

  • Nachricht senden

27

Donnerstag, 14. September 2017, 20:46

Ganz gut kommt man, wenn man sich bei jeder for Schleife vorstellt, daß das Konzept des Durchzählens da noch komplett unbekannt gewesen sein muß, weshalb Die Herren Kerninghan und Richie das nicht wissen konnte, und das darum einfach eine seltsame Abart einer while Schleife ist. Dann wird i.a. auch für PASCAL Menschen recht verständlich.

Und zu den Pointern noch: Ein wichtiger Punkt, der auch in Büchern oft nur so beiläufig "mit"erwähnt wird ist, das so ein C Pointer immer eine Typbindung hat. Soll heißen, der Pointer weiß, auf was für eine Struktur er zeigt und wieviel Platz die im Speicher benutzt. Also char* 1 Byte vs. int* 4 Byte. Nur dadurch funktionieren solche Konstrukte wie argv++ , also Adresse um 1 Byte vs. 4 Byte erhöhen, überhaupt. Auch das Bewegen in Arrays mittels eines Pointers basiert darauf, daß der Pointer weiß, was für Datentypen im Array liegen.
Interessante Fehler und Fehlermeldungen bekommt man, wenn man das nicht weiß und z.B. Pointer auf unterschiedliche Strukturen einander zuweist.
Ich weiß nicht mehr, wie das in Pascal war, aber im BBC Basic gibt es auch so eine Art Pointer, dort wird aber einfach eine Adresse gemerkt. Der zweite wichtige Teil eines C-Pointers, eben diese Typbindung, gibts da nicht.


( Und noch als Ergänzung zu "Sortieren per Extra-Array" respektive Doppelpointer: Man kann so eine sortierte Liste auch aufheben und eine zweite nach einem anderen Suchkriterium sortieren und eine dritte wieder anders. Da die nur Pointer enthalten sind, ist sie recht klein, aber das Ergebnis ist "instantan" da. Im Prinzip ist das was, was viele großen Datenbanken benutzen - oracle mal als Stichwort. Bei Neuaufnahmen von Daten müssen die halt genau einmal in diese Sortierlisten einsortiert werden - thats all. Es gibt also durchaus ein paar Anwendungen für sowas. )

Schroeder

Vereinsmitglied

Beiträge: 1 183

Wohnort: Haltern am See

Lieblingscomputer: Mein erster 286er von 1988, läuft immer noch.

  • Nachricht senden

28

Freitag, 15. September 2017, 12:41

Mahlzeit,

ich denke Pointer/Zeiger sind der Weg Speicherplatz zu sparen wenn man mit konstanten Zeichenketten arbeiten die eine unterschiedliche Länge haben.
Hier verliere ich bei einer Arraydeklaration unter Umständen viel Speicher. Selbst heutige Controller für Embedded Devices drücken einen doch starke Speicherlimitierungen auf. Da ist man schnell wieder 20 Jahre in der Vergangenheit.

Eine echte Hilfe sind Pointer aber bei verketteten Listen wie in meinem Beispiel vorher gezeigt. Ich arbeite bei meinen Fahrzeugprojekten sehr viel mit Strukturen, Unions und die Verlistung solcher. In den Strukturen deklariert man dann Zeiger auf die nächste Struktur.

Hier ein Beispiel für eine Warnungsausgabe für ein Cockpitdisplay im Auto wo die Struktur einmal Elemente "*content" für die formatierte Ausgabe, den Status der Warnung und einen Anzeigetimer enthält, wobei content wieder eine andere Struktur ist:

Quellcode

1
2
3
4
5
6
7
8
struct warning{
	struct warning *next;
	warningcontent *content;
.
.
.
	char timer;
}


Diese weise ich den Zeigern wbegin,wpointer und den Inhalten zu:

Quellcode

1
*wbegin,*wpointer,woelpressure,wairbag,wengine,woellevel,wcoolentlevel,wgen,wbreak,wbreaklever,wfluid,wgas,wfrost;


Dann bilde ich die Liste:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
	wbegin=&woelpressure;
	woelpressure.next=&wairbag;
	wairbag.next=&wengine;
	wengine.next=&woellevel;
	woellevel.next=&wcoolentlevel;
	wcoolentlevel.next=&wgen;
	wgen.next=&wbreak;
	wbreak.next=&wbreaklever;
	wbreaklever.next=&wgas;
	wgas.next=&wfluid;
	wfluid.next=&wfrost;
	wfrost.next=0;


Jetzt zeigt der Zeiger wbegin auf die Adresse der ersten Struktur: wbegin=&woelpressure und diese auf die nächste: woelpressure.next=&wairbag usw. Das letzte Element der Liste zeigt auf 0.

Und nun kann ich mit einer Schleife durch die Liste gehen und die Elemente abhandeln:

Quellcode

1
2
3
for(wpointer=wbegin;wpointer;wpointer=wpointer->next){
  if(wpointer->timer)...
}


Ich persönlich finde, das illustriert den Vorteil der Zeigertechnik.

Gruss,
Peter

29

Samstag, 16. September 2017, 09:40

Lest mal nach, warum die Herren Kernighan und Ritchie C kreiert haben. Damals mußte das Betriebssystem für jeden neuen Computertyp neu geschrieben werden, weil das alles Assemblerprogramme waren. Mit dem C-Compiler mußten im Prinzip nur die Assembler-Mnemonics geändert und der Code neu compiliert werden. Dementsprechend ist C eigentlich nur ein "Luxusassembler". Daher kommen solche Sachen wie "var++". Das wird einfach zu einem "inc var". Jeder Prozessor kann indirekt adressieren. Beim Z80 beispielsweise gibt es ein "ld a,(bc)". Da wird der Inhalt der Speicherzelle mit der Adresse, die in bc steht, in den Akku geladen. Damit ist (bc) ein Pointer. Diese Aufzählung könnte fortgesetzt werden.

Gruß Gerhard

Beiträge: 688

Wohnort: Dresden (nahebei)

Lieblingscomputer: Acorn RISC OS + +4

  • Nachricht senden

30

Dienstag, 19. September 2017, 11:25

Nu ja, also es gab schon durchaus Algol ( ok, kann man evtl. streichen ) , aber in benutzbar und bis heute in "Betrieb" : Fortran (!) ( super für SMP und SIMD ) , Basic , Cobol . Nicht nur Assembler.
Und eine Indirektion bei Ladebefehlen etc. auf Maschinensprachebene ist meist irgendwie begrenzt auf einen bestimmten Umgebungsbereich der mitübergebenen Adresse, wogegen ein vernünftiger Pointer den kompletten Adressraum abdecken kann.

Ähnliche Themen

Thema bewerten