home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / C / MAXON_C4.DMS / in.adf / Referenz-Handbuch < prev   
Encoding:
Text File  |  1994-11-01  |  127.6 KB  |  3,982 lines

  1. 1. Die ANSI C Includedateien
  2. In diesem Abschnitt werden die Includedateien besprochen, 
  3. die Bestandteil des ANSI C Standards sind. MaxonC++ 
  4. deklariert darin aber auch einige zusätzliche eigene 
  5. Funktionen und Symbole. Diese sind jeweils mit einem "[M]" 
  6. gekennzeichnet.
  7. 1.1 Verschiedene nützliche Funktionen: <stdlib.h>
  8. In der Include-Datei <stdlib.h> werden einige nützliche 
  9. Funktionen für die unterschiedlichsten Zwecke, z. B. zur 
  10. Umwandlung von Zahlen und für die Speicherverwaltung, 
  11. definiert.
  12. 1.1.1 Umwandlung zwischen Zahlen und Strings
  13.  
  14. strtol
  15.  
  16. long int strtol(const char *string, char **end, int base)
  17.  
  18.     Die Funktion "strtol" wandelt eine Zeichenkette in eine 
  19. ganze Zahl um. Am Anfang von "string" darf Leerraum stehen 
  20. und hinter der Zahldarstellung dürfen noch andere Zeichen 
  21. folgen. Wird für "end" ein Wert ungleich Null angegeben, 
  22. so wird ein Zeiger auf den nicht umgewandelten Teil der 
  23. Zeichenkette (z. B. auf die Zeichen, die der 
  24. Zahldarstellung folgen) in der Variablen, auf die "end" 
  25. verweist, abgelegt. Der Parameter "base" gibt die 
  26. gewünschte Basis an: bei einem Wert zwischen 2 und 36 wird 
  27. die Zeichenkette mit dieser Basis umgewandelt; ist der 
  28. Wert 0, hängt die Basis wie in C üblich vom Präfix der 
  29. Zeichenfolge ab (Hex bei "0x" oder "0X", oktal bei "0" und 
  30. andernfalls dezimal).
  31.     Wenn das Ergebnis den Bereich von "long int" über- oder 
  32. unterschreitet, wird "LONG_MAX" bzw. "LONG_MIN" 
  33. zurückgegeben und die Variable "errno" erhält den Wert 
  34. "ERANGE" (siehe <errno.h>).
  35.  
  36. strtoul
  37.  
  38. unsigned long strtoul(const char *string, char **end, int 
  39. base)
  40.  
  41.     Diese Funktion ist analog zu "strtol", aber der String 
  42. wird in ein vorzeichenloses Langwort umgewandelt und im 
  43. Falle eines Fehlers wird die Konstante "ULONG_MAX" 
  44. zurückgegeben.
  45.  
  46.  
  47. strtod
  48.  
  49. double strtod(const char *string, char **end)
  50.  
  51.     Auch diese Funktion wandelt den Anfang einer Zeichenkette 
  52. in eine Zahl um und zwar in einen "double"-Wert. Wie bei 
  53. "strtol" wird ein Zeiger auf den nicht umgewandelten Teil 
  54. der Zeichenkette in "*end" abgelegt, sofern "end" nicht 
  55. Null ist. Bei einem Überlauf ist das Ergebnis "HUGE_VAL", 
  56. bei einem Unterlauf wird "0" zurückgegeben.
  57.  
  58. strtovl [M]
  59.  
  60. long long strtovl(const char *string, char **end, int base)
  61.  
  62.     Diese Funktion entspricht "strtol", wandelt aber in einen 
  63. 64 Bit breiten "long long int"-Wert um, und im Falle eines 
  64. Überlaufs ist das Ergebnis "LONGLONG_MAX" bzw. 
  65. "LONGLONG_MIN".
  66.  
  67. strtouvl [M]
  68.  
  69. unsigned long long strtouvl(const char *s, char **end, int 
  70. base)
  71.  
  72.     Auch "strtouvl" führt in gewohnter Weise die Umwandlung 
  73. eines Strings durch und zwar nach "unsigned long long 
  74. int". Beim Überlauf wird "ULONGLONG_MAX" als Ergebnis 
  75. geliefert, sonst ist alles wie bei "strtol".
  76.  
  77. atoi
  78.  
  79. int atoi(const char *string)
  80.  
  81.     "atoi" wandelt eine dezimale Ziffernfolge in den 
  82. entsprechenden numerischen Wert um und entspricht damit 
  83. "(int) strtol(string, 0, 10)".
  84.  
  85. atol
  86.  
  87. long atol(const char *string)
  88.  
  89.     Auch diese Funktion ist nur eine vereinfachte Form von 
  90. "strtol" und entspricht "strtol(string, 0, 10)".
  91.  
  92. atof
  93.  
  94. double atof(const char *string)
  95.  
  96.     Noch eine Kurzform, diesmal aber im Fileßkommabereich: 
  97. Ein Aufruf von "atof" ist äquivalent zu "strtod(string, 
  98. 0)".
  99.  
  100. ERANGE
  101.  
  102. #define ERANGE 1000
  103.  
  104.     Diesen Wert erhält die Variable "errno", wenn bei 
  105. "strtol" oder den verwandten Funktionen ein Überlauf 
  106. auftritt.
  107.  
  108. HUGE_VAL
  109.  
  110. #define HUGE_VAL 1.797693134862316E+308
  111.  
  112.     Rückgabewert der Funktion "strtod" im Falle eines 
  113. Überlaufs.
  114. 1.1.2 Mathematische Funktionen
  115.  
  116. abs
  117.  
  118. int abs(int i)
  119.  
  120.     "abs" liefert den absoluten Betrag seines Arguments, also 
  121. so etwas wie "(i >= 0? +i : -i)".
  122.  
  123. labs
  124.  
  125. long int labs(long int l)
  126.  
  127.     Genau wie "abs", nur eben für "long int"-Werte. 
  128. Bekanntlich sind in MaxonC++ die internen Darstellungen 
  129. von "int" und "long" identisch (jeweils 32 Bit), so daß 
  130. auch diese beiden Funktionen sich praktisch nicht 
  131. unterscheiden.
  132.  
  133.  
  134. vlabs [M]
  135.  
  136. long long int vlabs(long long int vl)
  137.  
  138.     Noch eine Betragsfunktion, diesmal für "long long int" 
  139. und damit natürlich eine Spezialität von MaxonC++. Ganz 
  140. schön nervig, daß man in ANSI C nicht überladen kann...
  141.  
  142. div
  143.  
  144.  div_t div(int nenner, int zaehler)
  145.  
  146.     Da bei den üblichen Divisionsalgorithmen gleichzeitig 
  147. Quotient und Rest ermittelt werden, ist es natürlich 
  148. Zeitverschwendung, diese beiden Werte in zwei getrennten 
  149. Rechenschritten zu berechnen. Der Datentyp "div_t" ist 
  150. eine Struktur mit den Einträgen "quot" für den Quotienten 
  151. und "rem" für den Rest.
  152.  
  153. ldiv_t
  154.  
  155. ldiv_t ldiv(long nenner, long zaehler)
  156.  
  157.     Das Ganze noch einmal für "long"-Zahlen.
  158.  
  159. div_t
  160.  
  161. typedef struct {
  162.         int quot;
  163.         int rem;
  164.         } div_t
  165.  
  166.     In Strukturen dieses Typs werden die Ergebnisse der 
  167. Funktion "div" zurückgegeben.
  168.  
  169. ldiv_t
  170.  
  171. typedef struct {
  172.         long quot;
  173.         long rem;
  174.         } ldiv_t;
  175.  
  176.     ist die Ergebnis-Struktur der Funktion "ldiv".
  177. 1.1.3 Zufallszahlen
  178.  
  179. RAND_MAX
  180.  
  181. #define RAND_MAX 0x7fff
  182.  
  183.     Diese Konstante stellt das größtmögliche Ergebnis von 
  184. "rand" dar.
  185.  
  186. rand
  187.  
  188. int rand( void )
  189.  
  190.     "rand" liefert eine Pseudo-Zufallszahl im Bereich von 0 
  191. bis RAND_MAX. MaxonC++ verwendet hier das additive 
  192. Kongruenzverfahren, so daß ein Startwert definiert werden 
  193. muß und zwar mit der folgenden Funktion:
  194.  
  195. srand
  196.  
  197. void srand(unsigned int seed)
  198.  
  199.     Da die wenigsten Amigas einen 
  200. Hardware-Zufallszahlengenerator eingebaut haben (am besten 
  201. solche Dinger, die den Zerfall von Isotopen benutzen, denn 
  202. solche Vorgänge sind wirklich zufällig), berechnet "rand" 
  203. natürlich nur Pseudo-Zufallszahlen nach einem bestimmten 
  204. Algorithmus (s. o.). Dieser Algorithmus benötigt einen 
  205. Startwert, aus dem die erste Zufallszahl berechnet wird 
  206. (und dann jede weitere Zahl aus der vorhergehenden). 
  207. "srand" setzt diesen Startwert und sollte deshalb vor der 
  208. ersten Benutzung von "rand" aufgerufen werden.
  209.     Wenn Sie dabei einen konstanten Wert verwenden, etwa 
  210. "srand(4711)", erhalten Sie natürlich auch immer dieselbe 
  211. Folge von "Zufallszahlen". Deshalb ist es üblich, hier 
  212. einen Wert zu wählen, der von der Systemzeit abhängt, z. 
  213. B. "srand(time(0))".
  214.  
  215. Random [M]
  216.  
  217. unsigned Random(unsigned u)
  218. double Random()
  219.  
  220.     Dieser überladene Funktionsname ist eine Spezialität von 
  221. MaxonC++ und kann auch nur benutz werden, wenn <stdlib.h> 
  222. im C++-Modus compiliert wird. Mit einen ganzzahligen 
  223. Argument "u" liefert "Random" eine Zufallszahl im Bereich 
  224. von 0 bis u-1, ohne Argument eine Fließkommazahl zwischen 
  225. 0 und 1 (wobei 0 möglicherweise vorkommen kann, 1 aber 
  226. nicht). Diese Funktionen benutzen ein ähnliches Verfahren 
  227. wie "rand", beziehen aber die aktuelle Rasterzeile des 
  228. Videoausgangs in die Berechnung mit ein. Dadurch muß die 
  229. Zufallszahlenfolge nicht initialisiert werden und ist 
  230. deshalb wesentlich "zufälliger" als "rand".
  231.  
  232. 1.1.4 Speicherverwaltung, Typen und Zeiger
  233.  
  234. malloc
  235.  
  236. void malloc(size_t size)
  237.  
  238.     "malloc" reserviert "size" Bytes Speicher und gibt einen 
  239. Zeiger darauf zurück oder 0, wenn kein Speicher 
  240. angefordert werden konnte. "size_t" ist ein ganzzahliger 
  241. Datentyp, der unter MaxonC++ als "unsigned" definiert ist 
  242. und "zufällig" auch der Typ des Ergebnisses von "sizeof" 
  243. ist.
  244.     Mit der Funktion "set_new_handler" (siehe <new.h>) kann 
  245. eine Funktion spezifiziert werden, die so lange immer 
  246. wieder aufgerufen wird, bis genügend Speicher frei ist - 
  247. oder die Funktion mit "exit" o. Ä. aussteigt.
  248.  
  249. calloc
  250.  
  251. void *calloc(size_t anzahl, size_t size)
  252.  
  253.     Diese Funktion entspricht "malloc", reserviert aber 
  254. Speicher für einen "anzahl" Elemente großen Vektor des 
  255. Elementtyps "size".
  256.  
  257. free
  258.  
  259. void free(void *ptr)
  260.  
  261.     "free" gibt einen mit "malloc", "calloc" oder "realloc" 
  262. reservierten Speicherbereich wieder frei.
  263.  
  264.  
  265. realloc
  266.  
  267.  void *realloc(void *ptr, size_t size)
  268.  
  269.     Der Speicherplatzbedarf eines Objekts, auf das "ptr" 
  270. zeigt, wird auf "size" geändert und ein Zeiger auf das 
  271. (möglicherweise verschobene) Objekt zurückgegeben. 
  272. Natürlich muß es sich um ein Objekt handeln, das mit 
  273. "malloc", "calloc" oder einem anderen "realloc"-Aufruf 
  274. erzeugt wurde.
  275.     MaxonC++ verfährt dabei wie folgt:
  276.     Ist die neue Größe mit der alten identisch, muß nichts 
  277. getan werden, und der Zeiger "ptr" wird unverändert 
  278. zurückgegeben.
  279.     Andernfalls wird versucht, einen neuen Speicherbereich 
  280. der gewünschten Größe zu allozieren, und die passende 
  281. Anzahl von Bytes umkopiert. Das alte Objekt wird gelöscht 
  282. und ein Zeiger auf das neue zurückgegeben.
  283.     Kann kein neues Objekt eingerichtet werden, ist das 
  284. Ergebnis 0, und das ursprüngliche Objekt, auf das "ptr" 
  285. zeigt, bleibt unverändert.
  286. In der ersten Version wurde noch bei Verkleinerung ein 
  287. Teil des ursprünglichen Objekts freigegeben bzw. bei 
  288. Vergrößerung versucht, den unmittelbar angrenzenden 
  289. Speicher anzufordern. Das war zwar effektiv, widerspricht 
  290. aber den Amiga-Programmierrichtlinien und bereitet 
  291. insbesondere Tools wie "MemWall" Probleme.
  292.  
  293. size_t
  294.  
  295. typedef unsigned size_t
  296.  
  297.     "size_t" ist der Datentyp, der in C und C++ überall da 
  298. verwendet wird, wo es um die Größe irgendwelcher Objekte 
  299. geht.
  300.  
  301. NULL
  302.  
  303. #define NULL 0
  304.  
  305.     Eine Konstante, die manche Leute gern für Zeiger des 
  306. entsprechenden Werts verwenden. Eine Definition 
  307. "((void*)0)" wie in vielen anderen C-Systemen ist hier 
  308. übrigens nicht möglich, da C++ keine direkte Konvertierung 
  309. von "void*" in andere Zeigertypen kennt.
  310.  
  311.  
  312. wchar_t
  313.  
  314. typedef int wchar_t
  315.  
  316.     Der Datentyp von "langen" Zeichenkonstanten, z. B.
  317.         wchar_t C = L"x";
  318.  
  319. 1.1.5 Programmende
  320.  
  321. exit
  322.  
  323. void exit(int res)
  324.  
  325.     Diese Funktion beendet das Programm und entspricht einem 
  326. "return res" aus der Funktion "int main()". Mit "atexit" 
  327. eingehängte Funktione werden ausgeführt, Destruktoren für 
  328. globale Variablen aufgerufen und Resourcen (Dateien, 
  329. Speicher usw.) freigegeben. Das Ergebnis Null zeigt 
  330. normalerweise an, daß das Programm erfolgreich ausgeführt 
  331. wurde, und jeder andere Wert wird als Fehlernummer 
  332. interpretiert.
  333.  
  334. atexit
  335.  
  336. int atexit(void (*funktion)(void))
  337.  
  338.     teilt der Laufzeitbibliothek mit, daß die angegebene 
  339. parameterlose Funktion am Programmende ausgeführt werden 
  340. soll.
  341.  
  342. abort
  343.  
  344. void abort(void)
  345.  
  346.     Das Programm wird gnadenlos abgebrochen, ganz ohne 
  347. Destruktoren, "atexit"-Funktionen und Resourcen-Freigabe.
  348.  
  349.  
  350. 1.1.6 Kommunikation mit dem Betriebssystem
  351.  
  352. getenv
  353.  
  354. char *getenv(const char *name)
  355.  
  356.     Die Funktion liefert den Wert der Environment-Variablen 
  357. "name" und liefert einen Zeiger darauf oder Null, wenn 
  358. keine derartige Variable existiert.
  359.     Diese Funktion benötigt mindestens die Kickstart-Version 
  360. 2.0 (37.175) und liefert bei früheren Versionen stets Null.
  361.  
  362. system
  363.  
  364. int system(const char *command)
  365.  
  366. Die Funktion führt den in "command" beschriebenen 
  367. CLI-Befehl aus und liefert dessen Rückgabewert als 
  368. Ergebnis. Auch diese Funktion benötigt mindestens 
  369. Betriebssystemversion 2.0 und liefert andernfalls immer 
  370. "-1". Die Ausgaben der Funktion erfolgen über die 
  371. Standardausgabe des Prozesses - und in der 
  372. Entwicklungsumgebung MCPP ist dies bei 
  373. Betriebssystemversion 1.2 oder 1.3 leider die Umgebung, 
  374. aus der MaxonC++ einmal gestartet wurde, nämlich das 
  375. entsprechende CLI-Fenster oder "Nil:" beim Start von der 
  376. Workbench.AbBetriebssystemversion 2.0 werden die Ausgaben 
  377. korrekt umgelenkt.
  378.  
  379. 1.1.7 Sortieren und Suchen
  380.  
  381. qsort
  382.  
  383. void qsort(void *vektor, size_t anzahl, size_t size,
  384. int (*compare)(const void *, const void *))
  385.  
  386.     Diese Funktion sortiert den Vektor "vektor[0] ... 
  387. vektor[anzahl-1]", dessen Elemente jeweils die Größe 
  388. "size" haben, mit der angegebenen Vergleichsfunktion. In 
  389. Abschnitt 2.3.4 des Tutorials wird "qsort" ausführlich 
  390. beschrieben.
  391.  
  392.  
  393. bsearch
  394.  
  395. void *bsearch(const void *obj, const void *vektor,
  396.     size_t anzahl, size_t size,
  397.     int (*compare)(const void *, const void *))
  398.  
  399.     sucht im Vektor "vektor[0] ... vektor[anzahl-1]", dessen 
  400. Elemente jeweils die Größe "size" haben, anhand der 
  401. angegebenen Vergleichsfunktion ein Element, das mit "*obj" 
  402. übereinstimmt. Da die Suche binär erfolgt, muß der Vektor 
  403. dafür (z. B. mit "qsort") sortiert sein. Auch diese 
  404. Funktion wird in Abschnitt 2.3.4 des Tutorials näher 
  405. erläutert.
  406.  
  407. 1.2 Ein- und Ausgaben: <stdio.h>
  408. 1.2.1 Typen, Objekte und Konstanten
  409.  
  410. FILE
  411.  
  412. typedef struct stream FILE
  413.  
  414.     Der Datenstrom ist das Hauptkonzept der Ein- und Ausgabe 
  415. in ANSI C und entspricht einer Datei, die aber nicht 
  416. unbedingt wie eine Datei aussehen (also auf einer Diskette 
  417. oder Festplatte liegen) muß, sondern auch z. B. ein 
  418. Terminal, ein Window oder ein Drucker sein kann. Der 
  419. Datentyp, der solche Strom-Objekte beschreibt, heißt 
  420. "struct stream" oder "FILE".
  421.  
  422. std__in, std__out, std__err [M]
  423.  
  424. extern FILE std__in, std__out, std__err
  425.  
  426.     Dies sind die Namen der drei Standard-Dateien: "std__in" 
  427. für Eingaben des Programms, "std__out" für Ausgaben und 
  428. "std__err" für Fehlermeldungen. Auf dem Amiga sind der 
  429. Ausgabe- und der Fehlerkanal (leider) identisch. Beim 
  430. Programmstart sind diese Dateien geöffnet und 
  431. initialisiert (auch wenn sie beim Workbench-Start ins 
  432. Nirvana zeigen) und müssen am Programmende auch nicht 
  433. geschlossen werden.
  434.     Die drei Datenströme müssen keineswegs in jedem C-System 
  435. diese Namen tragen, sondern können durchaus anders heißen. 
  436. Deshalb sollte man sie nie unter diesen Bezeichnern 
  437. ansprechen, sondern nur mit den drei folgenden Makros:
  438.  
  439.  
  440. stdin, stdout, stderr
  441.  
  442. #define stdin (&std__in)
  443. #define stdout (&std__out)
  444. #define stderr (&std__err)
  445.  
  446.     Die meisten Funktionen, die etwas mit Ein- und Ausgabe 
  447. von Daten zu tun haben, erwarten als Argument keinen 
  448. Datenstrom, sondern einen Zeiger auf einen solchen. 
  449. Deshalb gibt es diese drei Makros, die jeweils einen 
  450. Zeiger auf eine Standard-Datei liefern.
  451.  
  452. NULL
  453.  
  454. #define NULL 0
  455.  
  456.     Die allseits beliebte Konstante (für Zeiger) wird auch in 
  457. dieser Include-Datei definiert.
  458.  
  459. size_t
  460.  
  461. typedef unsigned size_t
  462.  
  463.     "size_t" ist der Standardname für den Typ, den Ergebnisse 
  464. von "sizeof" haben.
  465.  
  466. EOF
  467.  
  468. #define EOF (-1)
  469.  
  470.     Die Konstante "EOF" wird an verschiedenen Stellen zum 
  471. Anzeigen des Dateiendes bzw. eines Fehlers benutzt.
  472.  
  473.  
  474. 1.2.2 Öffnen und Schließen von Dateien
  475.  
  476. fopen
  477.  
  478. FILE *fopen(const char *name, const char *modus)
  479.  
  480.     öffnet die Datei des angegebenen Namens und mit dem 
  481. angegebenen Modus, erzeugt dazu eine FILE-Struktur und 
  482. gibt einen Zeiger darauf zurück. Kann die Datei nicht 
  483. geöffnet werden, liefert die Fuktion Null.
  484.     Es gibt die folgenden Modi:
  485.     "r"    Vorhandene Datei zum Lesen öffnen.
  486.     "w"    Datei zum Schreiben öffnen bzw. erzeugen und dabei 
  487. evtl. vorhandene Datei überschreiben.
  488.     "a"    Existierende Datei zum Anhängen ans Dateiende öffnen 
  489. bzw. neue Datei erzeugen und zum Schreiben öffnen.
  490.     "r+"    Vorhandene Datei zum Lesen und Schreiben öffnen oder 
  491. ggf. eine neue Datei erzeugen.
  492.     "w+"    Eine neue Datei erzeugen (ggf. existierende Datei 
  493. löschen) und zum Lesen und Schreiben öffnen.
  494.     "a+"     Vorhandene Datei fürs Lesen und Schreiben öffnen 
  495. (ggf. neue Datei anlegen), wobei Schreib-/Leseposition auf 
  496. Dateiende gesetzt wird.
  497.     ANSI C unterscheidet zwischen Text- und Binärdateien. Die 
  498. oben aufgeführten Modi öffnen eine Datei als Textdatei. 
  499. Will man eine Binärdatei öffnen, ist ein "b" an die zweite 
  500. oder dritte Stelle des Modus-Strings zu setzen, z. B. 
  501. "rb", "rb+" oder "r+b".
  502.     Auf dem Amiga (wie auch unter UNIX) sind die beiden 
  503. Dateimodi identisch, und so ist es egal, ob Sie das 
  504. zusätzliche "b" angeben oder nicht. MS-DOS Computerund die 
  505. MessyDOS-Kopie Atari ST dagegen müssen tricksen und bei 
  506. Textdateien dem Programm vorgaukeln, daß die Folge 
  507. "Linefeed+Return" aus nur einem einzigen Zeichen besteht. 
  508.  
  509. fclose
  510.  
  511. int fclose(FILE *f)
  512.  
  513.     Eine geöffnete Datei muß auch wieder geschlossen werden. 
  514. Die Funktion "fclose" schließt eine Datei, die mit "fopen" 
  515. geöffnet wurde, und gibt die zugehörige "FILE"-Struktur 
  516. frei. Vorher werden natürlich alle Puffer geleert (wie bei 
  517. "fflush"). Das Ergebnis ist Null oder "EOF" bei einem 
  518. Fehler, aber auf dem Amiga kann beim Schließen einer Datei 
  519. nichts schiefgehen.
  520.  
  521. freopen
  522.  
  523. FILE *freopen(const char *name, const char *modus, FILE 
  524. *file)
  525.  
  526.     leitet einen bereits geöffneten Datenstrom in eine andere 
  527. Datei um. Die physikalische Datei, mit der "file" bisher 
  528. verbunden war, wird geschlossen, eine neue Datei mit dem 
  529. angegebenen Namen und Modus geöffnet und ein Verweis 
  530. darauf in die vorhandene FILE-Struktur gepackt.
  531.     Diese Funktion dient vor allem dazu, die 
  532. Standard-Datenströme "stdin", "stdout" oder "stderr" in 
  533. eine andere physikalische Datei umzuleiten.
  534.  
  535. FILENAME_MAX
  536.  
  537. #define FILENAME_MAX 200
  538.  
  539.     Der Amiga kennt es bekanntlich so gut wie keine 
  540. Beschränkung der Länge von Dateinamen, aber genau diese 
  541. maximale Länge soll "FILENAME_MAX" eigentlich angeben. Die 
  542. Konstante wurde mehr oder weniger willkürlich mit 200 
  543. definiert, denn länger wird ein Dateiname einschließlich 
  544. Pfad wohl kaum werden.
  545.  
  546. FOPEN_MAX
  547.  
  548. #define FOPEN_MAX 99999
  549.  
  550.     Dank dynamischer Datenorganisation ist die Anzahl der 
  551. Dateien, die Sie mit MaxonC++ öffnen dürfen, nicht 
  552. begrenzt und die Konstante "FOPEN_MAX" deshalb ziemlich 
  553. Banane. Begrenzt ist diese Anzahl lediglich dadurch, daß 
  554. irgendwann der Speicher voll ist oder das Betriebssystem 
  555. sich sonstwie beschwert.
  556.  
  557.  
  558. 1.2.3 Strings und Zeichenketten
  559.  
  560. fgetc
  561.  
  562. int fgetc(FILE *f)
  563.  
  564.     liest ein Zeichen aus der Datei "f" und wandelt es zuerst 
  565. in "unsigned char" und dann in "int" um, denn bekanntlich 
  566. gibt es in C keine klare Trennung zwischen Zahlen und 
  567. Zeichen. Wenn das Dateiende überschritten wurde oder sonst 
  568. ein Fehler auftrat, wird "EOF" geliefert.
  569.  
  570. getc
  571.  
  572. int getc(FILE *f)
  573.  
  574.     Diese Funktion ist witzigerweise mit "fgetc" identisch, 
  575. allerdings dürfen Implementationen sie aus nicht 
  576. nachvollziehbaren Gründen in Form eines Makros definieren. 
  577. Wie erst im Schwinden der Dominanz des Signifikats die 
  578. semantische Struktur der Horizontflucht, des steten 
  579. Aufschubs der Signifikation, entsteht, so wird 
  580. andererseits mit der Substitution des Signifikats durch 
  581. den Funktionszusammenhang der Signifikanten die 
  582. Horizonterfahrung als Motorik des ständigen Verweisens 
  583. ungültig.
  584.  
  585. getchar
  586.  
  587. int getchar (void)
  588.  
  589.     ist äquivalent zu "getc(stdin)", liest also ein Zeichen 
  590. aus der Standard-Eingabe.
  591.  
  592. ungetc
  593.  
  594. int ungetc(int c, FILE *f)
  595.  
  596.     Manchmal merkt man erst, daß man genug gelesen hat, wenn 
  597. man zuviel gelesen hat. Die Funktion "ungetc" stellt ein 
  598. bereits gelesenes Zeichen in eine Eingabedatei zurück, so 
  599. daß es beim nächsten Lesevorgang erneut gelesen wird. Bei 
  600. einer "echten" Datei kann man sich "ungetc" wie das 
  601. Zurücksetzten des Lesezeigers um ein Zeichen vorstellen, 
  602. aber bei einer interaktiven Eingabe geht das so natürlich 
  603. nicht. Deshalb hat jeder Datenstrom einen Puffer, in dem 
  604. solche "zurückgestellten" Zeichen aufgenommen werden. Es 
  605. paßt aber immer nur genau ein Zeichen in diesen Puffer.
  606.  
  607. fgets
  608.  
  609. char *fgets(char *s, int n, FILE *f)
  610.  
  611.     "fgets" liest eine Zeile mit höchstens "n-1" Zeichen aus 
  612. "f" und legt sie einschließlich eines abschließenden 
  613. Null-Bytes im String "s" ab. Als Zeilenende gilt entweder 
  614. ein Linefeed-Zeichen (â\n") oder das Dateiende (EOF). In 
  615. beiden Fällen wird das jeweilige Zeichen aber nicht in die 
  616. Stringvariable aufgenommen. Wurde das Dateiende bereits 
  617. überschritten oder trat ein Fehler auf, gibt "fgets" Null, 
  618. andernfalls "s" zurück.
  619.  
  620. gets
  621.  
  622. char *gets(char *s)
  623.  
  624.     entspricht "fgets(s, STREAM_MAXSTRING, stdin)", liest 
  625. also eine Zeile von der Standardeingabe.
  626.  
  627. STREAM_MAXSTRING [M]
  628.  
  629. #define STREAM_MAXSTRING 80
  630.  
  631.     Diese Konstante gibt an wieviele Zeichen maximal von 
  632. "gets" gelesen werden, ist aber nicht Bestandteil des ANSI 
  633. C-Standards.
  634.  
  635. fputc
  636.  
  637. int fputc(int c, FILE *f)
  638.  
  639.     Natürlich kann man nicht nur Daten lesen, sondern sie 
  640. auch schreiben. "fputc" ist die wohl rudimentärste 
  641. Ausgabefunktion und schreibt ein Zeichen "c" in eine Datei 
  642. "f". Das Ergebnis ist "EOF" bei Fehler oder andernfalls 
  643. das ausgegebene Zeichen.
  644.  
  645. putc
  646.  
  647. int putc(int c, FILE *f)
  648.  
  649.     Ähnlich wie "getc" und "fgetc", ist diese Funktion mit 
  650. "fputc" identisch, darf aber als Makro definiert sein. Sie 
  651. wissen ja, erst im Schwinden der Dominanz des Signifikats 
  652. entsteht...
  653.  
  654. putchar
  655.  
  656. int putchar(int c)
  657.  
  658.     schreibt das Zeichen in die Standard-Ausgabe und ist 
  659. damit identisch mit "putc(c, stdout)".
  660.  
  661. fputs
  662.  
  663. int fputs(const char *s, FILE *f)
  664.  
  665.     Diese Funktion schreibt eine Zeichenfolge, die wie üblich 
  666. mit einen Null-Zeichen enden muß, in die Datei "f". 
  667. Anstelle des abschließendne Nullbytes wird ein 
  668. Zeilenvorschub, also ein "\n", geschrieben.
  669.  
  670. puts
  671.  
  672. int puts(const char *s)
  673.  
  674.     dient ebenfalls zur Ausgabe von Zeichenketten und ist 
  675. äquivalent zu "fputs(s, stdout)".
  676.  
  677. 1.2.4 Formatierte Ausgabe
  678.  
  679. printf
  680.  
  681. int printf(const char *format, ...)
  682.  
  683.     Diese ungemein nützliche Funktion ist die 
  684. Standard-Ausgabefunktion in C, jedenfalls für Textdateien. 
  685. Im Prinzip wird dabei die Zeichenkette "format" 
  686. ausgegeben, nur an bestimmten Stellen werden andere Daten 
  687. eingesetzt. Diese "bestimmten Stellen" sind 
  688. Umwandlungsanweisungen, die stets mit einem "%" anfangen, 
  689. mit einem Buchstaben enden und dazwischen noch zusätzliche 
  690. Argumente haben dürfen. Ein Beispiel:
  691.         int a=17, b = 4;
  692.         printf("Die Summe von %d und %d ist %d.\n", a, b, a+b);
  693.     Die Zeichenfolge "%d" weist "printf" an, aus den 
  694. sonstigen Argumenten das nächste zu nehmen, als "int" zu 
  695. interpretieren und dezimal auszugeben. Also erzeugt der 
  696. obige Funktionsaufruf folgende Ausgabe:
  697.     Die Summe von 17 und 4 ist 21.
  698.     Natürlich gibt es nicht nur "%d", sondern eine ganze 
  699. Fülle von Format-Anweisungen, die folgendes in der 
  700. genannten Reihenfolge enthalten können oder müssen:
  701.     Das erste Zeichen ist, wie bereits erwähnt, stets "%".
  702.     Eine optionale Folge von Flags in beliebiger Reihenfolge: 
  703. Ein "-" bewirkt eine linksbündige Ausgabe der Daten (nur 
  704. sinnvoll, wenn eine Feldbreite angegeben wird, siehe 
  705. unten), "+" sorgt dafür, daß eine Zahl auf jeden Fall mit 
  706. Vorzeichen (also ggf. "+") ausgegeben wird, wogegen ein 
  707. Leerzeichen veranlaßt, daß bei vorzeichenlosen Zahlen ein 
  708. Leerzeichen an den Anfang gesetzt wird. Das Flag "0" füllt 
  709. bei Zahlen-Ausgaben das Ausgabefeld mit Nullen statt mit 
  710. Leerzeichen auf (ebenfalls nur sinnvoll, wenn Feldbreite 
  711. gesetzt), und "#" hat bei einigen Ausgabeformaten eine 
  712. besondere Wirkung: Hexadezimalen Ausgaben wird ein "0x", 
  713. oktalen eine "0" vorangestellt, Fließkommaausgaben 
  714. enthalten auf jeden Fall einen Dezimalpunkt und bei den 
  715. Anweisungen "g" und "G" werden Nullen am Ende nicht 
  716. unterdrückt. Welch" ein Satz!
  717.     Die Feldbreite und zwar als dezimale Ziffernfolge. Die 
  718. Ausgabe des umgewandelten Arguments erfolgt (sofern nicht 
  719. anders spezifiziert) linksbündig in einem Feld, das 
  720. mindestens diese Breite hat, wobei bei Bedarf mit 
  721. Leerzeichen (oder Nullen, siehe oben) aufgefüllt wird.
  722.     Die Genauigkeit, die mit einem "." anfängt (damit 
  723. "printf" sie von der Feldbreite unterscheiden kann), 
  724. ebenfalls als dezimale Ziffernfolge. Bei Zeichenketten 
  725. legt dies die maximale Anzahl von Zeichen fest, bei 
  726. ganzzahligen Ausgaben die minimale Anzahl von Ziffern 
  727. (nach links wird dann mit Nullen aufgefüllt) und bei 
  728. Fließkommazahlen die Anzahl der Dezimalstellen.
  729.     Ein Buchstabe als Längenangabe: Bei "h" ist das Argument 
  730. als "short" oder "unsigned short" zu betrachten, "l" weist 
  731. es als "long int" aus und bei "L" ist es entweder "long 
  732. double" oder "long long" oder "unsigned long long".
  733.     Das Umwandlungszeichen, z. B. "d" für ganzzahlige 
  734. dezimale Ausgaben.
  735.     Außer dem "%" am Anfang und dem Umwandlungszeichen am 
  736. Ende sind alle genannten Argumente optional. Als 
  737. Genauigkeit oder Feldbreite kann anstelle einer 
  738. Ziffernfolge "*" gesetzt werden. In diesem Fall steht der 
  739. fehlende numerische Wert als nächstes "int"-Argument in 
  740. der Argumentliste.
  741.  
  742.     Es gibt folgende Umwandlungszeichen:
  743.     Zeichen    Argumenttyp    Art der Ausgabe
  744.  
  745.     d    int    Dezimal
  746.     i    int    Wie "d"
  747.     o    int, unsigned    Vorzeichenlos oktal, ohne "0" am Anfang
  748.     x    int, unsigned    Vorzeichenlos hexadezimal ohne führendes
  749.             "0x" und mit kleinen Buchstaben
  750.     X    int, unsigned    Wie "x", aber mit Großbuchstaben
  751.     u    unsigned    Dezimal ohne Vorzeichen
  752.     c    int    Einzelnes Zeichen als "unsigned char"
  753.     s    char*    String, der mit Nullbyte endet
  754.     f     double    Fließkomma-Ausgabe in der Form "[-]xxx.yyy".
  755.             Die Genauigkeit legt die Anzahl der
  756.             Nachkommastellen fest, Default ist 6.
  757.     e    double    Exponentielle Darstellung "x.yyyyye›zzz",
  758.             wobei die Genauigkeit wieder die Zahl der
  759.             Nachkommastellen angibt (Default 6).
  760.     E    double    wie "e", aber mit großen "E": "x.yyyyyE›zzz"
  761.     g    double    Bei Argumenten, deren Exponent zwischen der
  762.             Genauigkeit (z. B. 6 als Default) und -4 liegt,
  763.             erfolgt die Ausgabe wie bei "f", andernfalls
  764.             wie bei "e".
  765.     G    double    Entspricht "g", aber es wird zwischen "f" und
  766.             "E" gewählt.
  767.     p    void*    Hexadezimale Speicheradresse
  768.     n    int*    Bewirkt keine Ausgabe, sondern legt
  769.             die Anzahl der bisher ausgegebenen Zeichen
  770.             in der Variablen, auf die das Argument zeigt,
  771.             ab.
  772.     %    -    Gibt ein Prozentzeichen aus.
  773.  
  774.     Das Ergebnis von "printf" ist die Anzahl der ausgegebenen 
  775. Zeichen oder negativ, wenn ein Fehler auftrat. Bitte 
  776. denken Sie stets daran, daß "printf" eine Funktion ohne 
  777. Netz und doppelten Boden ist und fehlerhafte Argumente 
  778. bestenfalls zu chaotischen Ausgaben und schlimmstenfalls 
  779. zu einem Systemabsturz führen können.
  780.  
  781.  
  782. fprintf
  783.  
  784. int fprintf(FILE *f, const char *format, ...)
  785.  
  786.     Diese Funktion arbeitet eigentlich genau wie "printf", 
  787. aber die Daten werden nicht über den 
  788. Standard-Ausgabestrom, sondern in die Datei "f" 
  789. ausgegeben. Andersrum formuliert, ist "printf(irgendwas)" 
  790. eine Abkürzung für "fprintf(stdout, irgendwas)".
  791.  
  792. sprintf
  793.  
  794. int sprintf(char *s, const char *format, ...)
  795.  
  796.     Auch diese Funktion entspricht "printf", aber die 
  797. Ausgaben werden nirgendwo wirklich ausgegeben, sondern im 
  798. String "s" abgelegt und mit einem Nullzeichen 
  799. abgeschlossen. Sie als Programmierer sind selbst dafür 
  800. verantwortlich, daß der Ziel-String groß genug ist, denn 
  801. andernfalls wird (wie in C nicht anders zu erwarten) 
  802. gnadenlos über den Vektor hinaus geschrieben, und der Guru 
  803. gerät ins Meditieren.
  804.  
  805. vprintf, vfprintf, vsprintf
  806.  
  807. typedef unsigned va_list;
  808.  
  809. int vprintf(const char *format, va_list arg);
  810.  
  811. int vfprintf(FILE *f, const char *format, va_list arg);
  812.  
  813. int vsprintf(char *s, const char *format, va_list arg);
  814.  
  815.     Diese Funktionen sind absolut äquivalent zu ihren 
  816. Entsprechungen ohne das "v" am Anfang, aber die Argumente, 
  817. die sonst dem Formatstring folgen, werden hier durch eine 
  818. variable Argumentenliste ("va_list") übergeben. Bitte 
  819. lesen Sie dazu auch das Kapitel über <stdarg.h> oder 
  820. fragen Sie Ihren Arzt oder Apotheker.
  821.  
  822.  
  823. 1.2.5 Formatierte Eingabe
  824.  
  825. scanf
  826.  
  827. int scanf(const char *format, ...)
  828.  
  829.     Was "printf" für die Ausgabe, ist "scanf" für die 
  830. Eingabe. Der Formatstring ist ähnlich aufgebaut wie bei 
  831. "printf", hat aber eine andere Bedeutung:
  832.     Leerzeichen oder Tabulatoren in der Formatzeichenkette 
  833. werden ignoriert. Bei allen anderen Zeichen außer "%" 
  834. erwartet "scanf", daß dieses Zeichen als nächstes in der 
  835. Eingabe folgt (eventuell mit vorangehenden Leerzeichen) 
  836. und liest es bzw. bricht ab, wenn das Zeichen nicht folgt. 
  837. Wieder leitet "%" Umwandlungsanweisungen ein.
  838.     Einem "%" kann optional ein "*" folgen (dann werden zwar 
  839. Zeichen gelesen und umgewandelt, aber nirgendwo abgelegt), 
  840. oder eine Zahl, die die maximale Feldbreite festlegt, also 
  841. die maximale Anzahl von Zeichen, die bei dieser Umwandlung 
  842. gelesen werden sollen. Die optionalen Zeichen "h", "l" und 
  843. "L" legen wie bei "printf" die Datenbreite fest.
  844.     Zu jeder Umwandlungsanweisung gehört in der restlichen 
  845. Argumentliste ein Zeiger auf eine Variable, es sei denn, 
  846. hinter dem "%" folgt ein "*" (siehe oben). Bei einer 
  847. Umwandlung überliest "scanf" zunächst alle 
  848. Zwischenraumzeichen einschließlich Zeilentrennern, liest 
  849. eine Zeichenfolge ein, die der Umwandlungsanweisung 
  850. entspricht, z. B. eine Ziffernfolge bei 
  851. dezimal-ganzzahliger Umwandlung, wandelt diese um und legt 
  852. das Ergebnis an der beschriebenen Stelle ab. Wenn ein 
  853. Fehler auftritt, bricht "scanf" sofort ab.
  854.  
  855.     Bei den bereits mehrfach erwähnten Umwandlungszeichen 
  856. handelt es sich um die Folgenden:
  857.     Zeichen    Argument     Erwartete Eingabedaten und Umwandlung
  858.  
  859.     d    int*    Dezimal, ganzzahlig
  860.     i    int*    Ganzzahlig, wahlweise dezimal, oktal (mit "0"
  861.             beginnend) oder hex (mit "0x" oder "0X" am Anfang)
  862.     o    int*    Oktal, ganzzahlig
  863.     x     int*    Hexadezimal mit oder ohne "0x"
  864.     c    char*    So viele Zeichen, wie die Feldbreite angibt 
  865. (Default
  866.             ist 1), wobei Leerzeichen, Zeilentrenner o. Ä. nicht
  867.             überlesen werden. Will man ein Zeichen lesen, vorher
  868.             aber Zwischenraumzeichen überlesen, ist die
  869.             Umwandlung "%1s" zu wählen. Im Gegensatz zu
  870.             "%s" wird bei "%c" kein Nullbyte angehängt.
  871.     s    char*    Überliest zuerst Leerzeichen und Tabulatoren und 
  872. liest
  873.             dann eine Folge von Nicht-Zwischenraum-Zeichen.
  874.             Ein Nullbyte wird an das Ergebnis angehängt.
  875.     e,f,g    float*    Fließkommazahl in nahezu beliebigem Format 
  876. (mit
  877.             oder ohne Voerzeichen, mit oder ohne Exponent, der
  878.             ein großes "E" oder ein kleines "e" haben darf usw.)
  879.     p    int*    Hexadezimale Zahl
  880.     n    int*    Liest nichts, sondern legt im Argument die Anzahl 
  881. der
  882.             bisher gelesenen Zeichen ab.
  883.     [...]    char*    Längste Zeichenkette, die ausschließlich aus 
  884. den
  885.             Zeichen zwischen "[" und "]" besteht, z. B.
  886.             Ziffernfolgen bei Umwandlungsoperator
  887.             "%[0123456789]". Auch hier kann
  888.             die Länge durch Setzen einer Feldbreite beschränkt
  889.             werden. Will man das Zeichen "]" aufnehmen, ist es an
  890.             den Anfang zu setzen (z. B. "%[ ]abcde]"). Die
  891.             gelesenen Zeichen werden wie üblich mit einem â\0"
  892.             abgeschlossen.
  893.     [^...]    char*    Liest die längste Zeichenkette, deren 
  894. Zeichen sich
  895.             nicht in der angegebenen Menge befinden.
  896.     %    -    Erwartet ein "%", legt es aber nirgendwo ab.
  897.  
  898.     Natürlich kann statt eines Zeigers auf "int" stets ebenso 
  899. gut ein Zeiger auf "unsigned int" verwendet werden. Bei 
  900. ganzzahligen Umwandlungsoperationen wird das zugehörige 
  901. Zeigerargument durch die Längenangabe âh" als "short" 
  902. betrachtet, âl" macht daraus "long" und âL" "long long". 
  903. Bei den Fließkommaoperationen ist âl" für 
  904. "double"-Variablen und âL" für "long double"-Variablen zu 
  905. setzen.
  906.  
  907.     Beispiel:
  908.         int i,j;
  909.         short s;
  910.         char c[80];
  911.         
  912.         scanf("Test %d %i, %hi %79s", &i, &j, &s, c)
  913.         
  914.     akzeptiert z. B. die Eingabe
  915.         Test 42 0x686b, 99 Rest
  916.         
  917.     oder auch
  918.         Test42 26731      ,99Rest
  919.  
  920.     Das Ergebnis von "scanf" ist in beiden Fällen 4, und in 
  921. die Variablen werden die Werte "42", "26731", "99" und 
  922. "Rest" eingelesen.
  923.     Mehr noch als "printf" ist "scanf" eine höchst unsichere 
  924. Funktion, da keine wirkliche Typprüfung der Argumente 
  925. vorgenommen wird. Wenn man "nur" ein "&" vergißt (und 
  926. damit den Wert einer Variablen statt ihrer Adresse als 
  927. Argument übergibt), ist der Hangup oft nicht mehr zu 
  928. vermeiden.
  929.  
  930. fscanf
  931.  
  932. int fscanf(FILE *f, const char *format, ...)
  933.  
  934.     Dies ist das Äquivalent zu "scanf" für beliebige Dateien.
  935. scanf(arglist)
  936.  
  937.     ist gleichbedeutend mit
  938. fscanf(stdin, arglist)
  939.  
  940.     wobei "arglist" hier nichts mit Niedertracht und 
  941. Heimtücke zu tun hat, sondern eine Argument-Liste 
  942. darstellen soll.
  943.  
  944.  
  945. sscanf
  946.  
  947. int sscanf(char *s, const char *format, ...);
  948.  
  949.     ist ebenfalls eine andere Form von "scanf". Hier wird die 
  950. Eingabe aus dem String "s" gelesen. Beispielsweise wandelt
  951.         sscanf(s, "%i", &n)
  952.  
  953.     die Ziffernfolge "s" in eine Zahl um und leistet dabei 
  954. ähnliches wie
  955.         n = atoi(s)
  956.  
  957. 1.2.6 Dateioperationen
  958. 1.2.6.1 Dateiende und Fehlerbehandlung
  959.  
  960. feof
  961.  
  962. int feof(FILE *f)
  963.  
  964.     liefert einen Wert ungleich Null, wenn in der genannten 
  965. Datei das Dateiende überschritten wurde.
  966.  
  967. ferror
  968.  
  969. int ferror(FILE *f)
  970.  
  971.     Diese Funktion schaut nach, ob bei der Datei "f" bisher 
  972. ein Fehler aufgetreten ist und vermerkt wurde, und liefert 
  973. die Fehlernummer oder andernfalls Null.
  974.  
  975. clearerr
  976.  
  977. void clearerr(FILE *f)
  978.  
  979.     löscht die Dateiende- und Fehlervermerke einer Datei, so 
  980. daß anschließend "feof" und "ferror" jeweils Null ergeben.
  981.  
  982.  
  983. 1.2.6.2 Puffern
  984.  
  985. setvbuf
  986.  
  987. int setvbuf(FILE *f, char *buf, int mode, unsigned size)
  988.  
  989.     Normalerweise gehen Ausgabeoperationen erheblich 
  990. schneller, wenn man die Daten nicht in kleinen 
  991. Kleckermengen (z. B. Zeichenweise) schreibt, sondern sie 
  992. erst einmal in einem Puffer sammelt und dann auf einen 
  993. Schlag schreibt. Das gilt vor allem unter den alten 
  994. Amiga-Systemversionen mit diesem unsäglich lahmen 
  995. BCPL-DOS, aber auch unter 2.0 und höchstwahrscheinlich 
  996. auch allen folgenden Versionen. Der Grund ist ganz einfach 
  997. der, daß bei jeder Ausgabeoperation ein erheblicher 
  998. Overhead nötig ist: Das Programm ruft eine DOS-Funktion 
  999. auf, das DOS gibt an das File-System weiter, welches 
  1000. wiederum ein Device befragt, und erst das betätigt dann 
  1001. (z. B.) den Controller, der dann mit der Festplatte 
  1002. kommuniziert... Dieser Overhead ist für jede Datengröße 
  1003. praktisch identisch, so daß es natürlich Zeit spart, wenn 
  1004. man das ganze Prozedere nur einmal für einen großen 
  1005. Datenblock durchexerziert und nicht für jedes Byte 
  1006. einzeln. Analog gilt das natürlich auch für Eingaben aus 
  1007. einer Datei.
  1008.     Die Funktion "setvbuf" versieht eine Datei mit einem 
  1009. solchen Puffer. Man kann sie für jede Datei nur einmal 
  1010. aufrufen, und zwar unmittelbar nach dem Öffnen, d. h. vor 
  1011. jeder Ein- und Ausgabe oder sonstigen Operation. "buf" 
  1012. zeigt dabei auf einen hinreichend großenSpeicherbereich, 
  1013. beim Wert Null legt "setvbuf" selbstständig einen solchen 
  1014. Puffer an und löscht ihn beim Schließen der Datei auch 
  1015. wieder. Der Parameter "size" gibt die gewünschte 
  1016. Puffergröße an. Erfahrungsgemäß sind hier einige hundert 
  1017. Bytes genug und eine weitere Steigerung bringt nicht mehr 
  1018. viel, und "mode" gibt einen der im folgenden beschriebenen 
  1019. Puffermodi an. Das Ergebnis von "setvbuf" ist Null, wenn 
  1020. alles klar ging.
  1021.  
  1022. IOFBF
  1023.  
  1024. #define _IOFBF 1
  1025.  
  1026.     Beim Modus "_IOFBF" puffert "setvbuf" vollständig, d. h. 
  1027. der Puffer wird immer komplett gefüllt, bevor eine neue 
  1028. Operation erfolgt.
  1029.  
  1030. IOLBF
  1031.  
  1032. #define _IOLBF (-1)
  1033.  
  1034.     Bei Ausgaben wird der Puffer im Modus "_IOLBF" höchstens 
  1035. bis zum ersten Zeilenende gefüllt. Dieser Modus ist z. B. 
  1036. auch bei  Bildschirmausgaben brauchbar und bringen sogar 
  1037. eine gewisse Beschleunigung.
  1038. IONBF
  1039.  
  1040. #define _IONBF 0
  1041.  
  1042.     Es wird nichts gepuffert. Einen Aufruf von "setvbuf" mit 
  1043. diesem Modus kann man sich also eigentlich sparen.
  1044.  
  1045. setbuf
  1046.  
  1047. void setbuf(FILE *f, char *buf)
  1048.  
  1049.     Dies ist eine Spar-Version von "setvbuf", bei der "buf" 
  1050. auf einen Puffer der Größe "BUFSIZ" zeigen. "setbuf" legt 
  1051. nicht selbstständig einen Speicherbereich der geforderten 
  1052. Größe an.
  1053.         char b[BUFSIZ];
  1054.         FILE *f;
  1055.         
  1056.         setbuf(f, b);
  1057.         
  1058.     ist äquivalent zu
  1059.         setvbuf(f, b, _IOFBF, BUFSIZ);
  1060.         
  1061.     Fehler können bei "setbuf" nicht auftreten, und somit ist 
  1062. das Ergebnis "void".
  1063.  
  1064. BUFSIZ
  1065.  
  1066. #define BUFSIZ 200
  1067.  
  1068.     ist die Puffergröße, die bei "setbuf" angenommen wird.
  1069.  
  1070. fflush
  1071.  
  1072. int fflush(FILE *f)
  1073.  
  1074.     klingt zwar irgendwie gestottert, wirkt aber in 
  1075. Wirklichkeit einer stoßweisen Stotter-Ausgabe (will sagen: 
  1076. Schreiben mit Puffer) entgegen: Die Daten, die sich gerade 
  1077. im Puffer der Datei befinden, werden geschrieben, und der 
  1078. Puffer wird gelöscht. Bei Eingabe-Dateien hat "fflush" 
  1079. keine Wirkung, und wenn als Argument Null gewählt wird, 
  1080. werden alle gerade geöffneten Dateien geflusht.
  1081.  
  1082. 1.2.6.3 Externe Dateien
  1083.  
  1084. remove
  1085.  
  1086. int remove(const char *name)
  1087.  
  1088.     entfernt die Datei dieses Namens, entspricht also dem 
  1089. CLI-Befehl "delete". Hat das geklappt, ist das Resultet 
  1090. Null, andernfalls die Fehlernummer.
  1091.  
  1092. rename
  1093.  
  1094. int rename(const char *oldname, const char *newname)
  1095.  
  1096.     benennt die Datei "oldname" in "newname" um, oder 
  1097. versucht es zumindest. Im Erfolgsfall wird Null als 
  1098. Ergebnis geliefert und andernfalls eine Fehlernummer.
  1099.  
  1100. tmpnam
  1101.  
  1102. char *tmpnam (char s[L_tmpnam])
  1103.  
  1104.     Manchmal steht man vor der Situation, daß man einige 
  1105. Daten in temporären Dateien ablegen will. Die Funktion 
  1106. "tmpnam" liefert dafür Dateinamen, die garantiert mit 
  1107. keiner existierenden Datei überein stimmen: Sie beginnen 
  1108. mit "t:TMP_", und im Rest der Zeichenfolge sind die 
  1109. Adresse der Taskstruktur, die laufende Nummer des 
  1110. "tmpnam"-Aufrufs, das Datum und die Uhrzeit kodiert.
  1111.     Der Parameter "s" muß auf eine Stringvariable der Länge 
  1112. (mindestens) "L_tmpnam" zeigen, in der das Ergebnis 
  1113. abgelegt wird, oder Null sein, dann wird der Dateiname in 
  1114. einem internen Buffer abgelegt. In beiden Fällen wird als 
  1115. Ergebnis ein Zeiger auf den String geliefert. "tmpnam" 
  1116. erzeugt keine Datei, sondern schlägt nur einen Namen vor. 
  1117. Außerdem stehen höchstens "TMP_MAX" verschiedene Namen zur 
  1118. Verfügung, aber bei MaxonC++ sind das mehr als genug.
  1119.         L_tmpnam
  1120.         
  1121.         #define L_tmpnam 40
  1122.         
  1123.     Die Konstante gibt an, wie groß ein String wenigstens 
  1124. sein muß, um das Ergebnis von "tmpnam" aufzunehmen.
  1125.  
  1126.         TMP_MAX
  1127.  
  1128.         #define TMP_MAX 0x10000
  1129.     "tmpnam" kann TMP_MAX mal aufgerufen werden, bevor sie 
  1130. sich wiederholt. In MaxonC++ sind das offensichtlich mehr 
  1131. als genug mögliche Dateinamen, aber darauf sollte man sich 
  1132. nicht verlassen - man denke hier nur an MesSy-DOS, wo 
  1133. Dateinamen nur 8+3 Zeichen lang sein dürfen. Übrigens muß 
  1134. man sich ganz schön beeilen, wenn man mit "tmpnam" 
  1135. wirklich zweimal denselben Namen erhalten will, denn 
  1136. MaxonC++ codiert ja auch die Uhrzeit in den Namen ein.
  1137.  
  1138. tmpfile
  1139.  
  1140. FILE *tmpfile (void)
  1141.  
  1142.     ist so etwas wie die Kombination von "tmpnam" mit "fopen" 
  1143. und einer Löschautomatik: Eine temporäre Datei wird mit 
  1144. dem Modus "wb+" geöffnet, und beim Schließen dieser Datei 
  1145. oder am Programmende wird sie automatisch wieder gelöscht. 
  1146. Wenn das Ganze ein Schlag ins Wasser war, liefert 
  1147. "tmpfile" Null, andernfalls einen Zeiger auf die Datei.
  1148.  
  1149. 1.2.6.4 Binäre Daten
  1150.  
  1151. fread
  1152.  
  1153. unsigned fread(void *ptr,
  1154. unsigned size, unsigned n, FILE *f)
  1155.  
  1156.     "fread" liest aus der Datei "f" in den Vektor "ptr" 
  1157. maximal "n" Objekte der Größe "size". Bitte fragen Sie 
  1158. nicht, warum man hier und bei "fwrite" erst "size" und 
  1159. dann "n" angeben soll, während es bei "calloc", "qsort" 
  1160. und "bsearch" genau umgekehrt ist. "fread" liefert als 
  1161. Ergebnis die Anzahl der gelesenen Objekte (nicht Bytes!), 
  1162. die natürlich keineswegs größer, aber durchaus geringer 
  1163. als "n" sein kann (z. B. wenn das Dateiende erreicht 
  1164. wurde).
  1165.  
  1166. fwrite
  1167.  
  1168. unsigned fwrite(const void *ptr, unsigned size, unsigned 
  1169. n, FILE *f)
  1170.  
  1171.     ist das Gegenstück zu "fread" und schreibt "n" Elemente 
  1172. der Größe "size" aus dem Vektor "ptr" in die Datei "f". 
  1173. Resultat ist die Anzahl der geschriebenen Objekte, die im 
  1174. Falle eines Fehlers kleiner als "n" ist.
  1175.  
  1176. 1.2.6.5 Positionieren in Dateien
  1177.  
  1178. fseek
  1179.  
  1180. int fseek(FILE *f, long offset, int modus)
  1181.  
  1182.     setzt den Schreib- bzw. Lesezeiger in einer Datei an eine 
  1183. andere Position. Es gibt drei Modi: "SEEK_SET" geht an die 
  1184. angegebene absolute Position (Dateianfang ist Null), 
  1185. "SEEK_CUR" verschiebt den Zeiger um den Offset, und bei 
  1186. "SEEK_END" bezieht sich der Offset auf das Dateiende, also 
  1187. z. B. "-1" für das letzte Byte der Datei. Die Funktion 
  1188. liefert im Falle eines Fehlers einen von Null 
  1189. verschiedenen Wert.
  1190.  
  1191.         SEEK_CUR, SEEK_SET, SEEK_END
  1192.  
  1193.         #define SEEK_CUR 0
  1194.         #define SEEK_END 1
  1195.         #define SEEK_SET (-1)
  1196.  
  1197.     Dies sind die drei Modi, die bei "fseek" angegeben werden 
  1198. können.
  1199.  
  1200. ftell
  1201.  
  1202. long ftell(FILE *f)
  1203.  
  1204.     liefert die aktuelle Dateiposition von Datei "f".
  1205.  
  1206. rewind
  1207.  
  1208. void rewind(FILE *f)
  1209.  
  1210.     setzt die Datei "f" an den Anfang zurück und löscht das 
  1211. Fehlerflag. Damit ist "rewind(f)" eine Abkürzung für 
  1212. "fseek(f, 0, SEEK_SET)" mit anschließendem "clearerr(f)".
  1213.  
  1214. fpos_t
  1215.  
  1216. typedef int fpos_t
  1217.  
  1218.     Der Datentyp "fpos_t" wird gebraucht, weil einige 
  1219. Implementierungen zwischen Text- und Binärdateien 
  1220. unterscheiden und die Anwendung "fseek" dann bei 
  1221. Textdateien etwas problematisch ist. Deshalb gibt es 
  1222. speziell für Textdateien die beiden folgenden Funktionen:
  1223. fgetpos
  1224.  
  1225. int fgetpos(FILE *f, fpos_t *posn)
  1226.  
  1227.     "fgetpos" speichert die aktuelle Position der Datei "f" 
  1228. in "posn", insbesondere zur späteren Verwendung mit 
  1229. "fsetpos". Wenn das System selbst nicht so genau weiß, was 
  1230. diese Posotion ist, liefert "fgetpos" einen Wert ungleich 
  1231. Null.
  1232.  
  1233. fsetpos
  1234.  
  1235. int fsetpos(FILE *f, const fpos_t *posn)
  1236.  
  1237.     Das versprochene Gegenstück zu "fgetpos": Die Datei wird 
  1238. wieder auf die Position gesetzt, die in "posn" mittels 
  1239. "fgetpos" abgespeichert wurde.
  1240.  
  1241. 1.2.7 Sonstige Funktionen
  1242.  
  1243. perror
  1244.  
  1245. void perror(const char *s)
  1246.  
  1247.     gibt eine Fehlermeldung aus, die sich zum einen aus dem 
  1248. String "s" und zum anderen aus der Fehlermeldung, die zu 
  1249. der Nummer gehört, die gerade in "errno" steht. Hat 
  1250. "errno" z. B. den Wert 205, gibt
  1251.  
  1252.         perror("Das war wohl nichts")
  1253.     aus:
  1254.     Das war wohl nichts: Object not found
  1255.     "errno" wird eigentlich immer gesetzt, wenn irgend etwas 
  1256. schief geht, z. B. wenn eine Datei nicht geöffnet werden 
  1257. kann. Näheres steht in <errno.h>.
  1258.  
  1259. exit
  1260.  
  1261. void exit(int res)
  1262.  
  1263.     lesen Sie hierzu bitte in Kapitel 1.1.5 (stdlib.h) nach.
  1264.  
  1265. 1.3 Fehlersuche: <assert.h>
  1266.  
  1267. assert
  1268.  
  1269. #ifdef NDEBUG
  1270. #define assert(C)
  1271. #else
  1272. extern "Asm" void do__assert(char*, char*, unsigned int);
  1273. #define assert(C) { if(!(C)) do__assert(#C, __FILE__, 
  1274. __LINE__); }
  1275. #endif
  1276.  
  1277.     Die Include-Datei "assert.h" definiert lediglich ein 
  1278. einziges Makro nämlich "assert". Man kann damit die 
  1279. Sicherheit seines Programms erhöhen, indem man 
  1280. Plausibilitätstests einführt. Wenn z. B. eine Funktion 
  1281. einen Parameter zwischen 0 und 42 erwartet, setze man an 
  1282. ihren Anfang folgendes:
  1283.         int f(int i)
  1284.         {
  1285.         assert( i>0 && i<42 )
  1286.         
  1287.         i++;        // usw.
  1288.         
  1289.     Gilt die bei "assert" angegebene Bedingung nicht, steigt 
  1290. das Programm bei einem ungültigen Parameter mit einer 
  1291. Meldung wie
  1292.         Assertion failed: i>0 && i<42, file "murx.cpp", line 4711
  1293.  
  1294.     aus - es sei denn, man definiert das Makro "NDEBUG", 
  1295. bevor man es einbindet. In diesem Fall werden die 
  1296. "assert"-Anweisungen ersatzlos gestrichen und kosten so 
  1297. weder Laufzeit noch Speicherplatz. Man sollte "NDEBUG" 
  1298. immer erst dann definieren, wenn man der Meinung ist, das 
  1299. Programm sei fehlerfrei. Auf jeden Fall aber vermeide man 
  1300. Bedingungen mit Seiteneffekt:
  1301.  
  1302.         FILE *fp;
  1303.         assert(fp = fopen("Caddy.config", "r"))       // NEIN!
  1304.         
  1305.     Diese Anweisung gibt zwar eine mehr oder weniger 
  1306. aussagekräftige Fehlermeldung ab, wenn das Programm seine 
  1307. Konfigurationsdatei nicht finden kann, und steigt dann 
  1308. aus, was durchaus sinnvoll ist - aber irgendwann kommt man 
  1309. vielleicht doch noch auf die Idee, "NDEBUG" zu definieren, 
  1310. und dann wird man sich wundern.
  1311.  
  1312. 1.4 Zeichenklassen: <ctype.h>
  1313. In der Definitionsdatei <ctype.h> findet der Programmierer 
  1314. einige kleine, aber recht nützliche Funktionen, durch die 
  1315. Zeichen weitgehend unabhängig vom verwendeten Rechner und 
  1316. Zeichencode behandelt werden können. Dies ist enorm 
  1317. wichtig für saubere (d. h. portable) Programmentwicklung.
  1318.  
  1319. isalnum, isalpha, iscntrl, isdigit, isgraph, islower,
  1320. isprint, ispunct, isspace, isupper, isxdigit
  1321.  
  1322. int isalnum (int c)
  1323. int isalpha (int c)
  1324. int iscntrl (int c)
  1325. int isdigit (int c)
  1326. int isgraph (int c)
  1327. int islower (int c)
  1328. int isprint (int c)
  1329. int ispunct (int c)
  1330. int isspace (int c)
  1331. int isupper (int c)
  1332. int isxdigit(int c)
  1333.  
  1334.     Diese Funktionen testen, ob das Zeichen "c" zu einer 
  1335. bestimmten Zeichgenklasse gehört, und liefern dann den 
  1336. entsprechenden logischen Wert (also "0" oder "1"). Es gibt 
  1337. prinzipiell folgende Klassen von Zeichen:
  1338.  
  1339.     Großbuchstaben von âA" bis âZ"
  1340.     Kleinbuchstaben von âa" bis âz"
  1341.     Allgemeine Buchstaben, d. h. Groß- oder Kleinbuchstaben. 
  1342. Umlaute werden dabei jeweils leider nicht berücksichtigt.
  1343.     Dezimale Ziffern von â0" bis â9"
  1344.     Hexadezimale Ziffern: â0" bis â9", âA" bis âF" sowie âa" 
  1345. bis âf"
  1346.     Leerraum, d. h. Leerzeichen, Zeilentrenner (Linefeed), 
  1347. Tabulatoren, Rücklauf (Return) und Seitenvorschub
  1348.     Sichtbare Zeichen einschließlich des Leerzeichens - das 
  1349. sind auf dem Amiga die Codes von 0x20 bis 0x7F sowie von 
  1350. 0xA0 bis 0xFF.
  1351.     Steuerzeichen, d. h. das genaue Gegenteil der sichtbaren 
  1352. Zeichen
  1353.     Die folgende Liste gibt an, welche Funktion bei welcher 
  1354. Zeichenklasse "wahr" liefert:
  1355.     isalnum    Buchstabe oder Ziffer
  1356.     isalpha    Buchstabe
  1357.     iscntrl        Steuerzeichen
  1358.     isdigit        Dezimale Ziffer
  1359.     isgraph    Sichtbares Zeichen außer Leerzeichen
  1360.     islower    Kleinbuchstabe
  1361.     isprint        Sichtbares Zeichen
  1362.     ispunct    Sichtbares Zeichen außer Leerzeichen, Buchstabe 
  1363. oder Ziffer
  1364.     isspace    Leerraum-Zeichen
  1365.     isupper    Großbuchstabe
  1366.     isxdigit    Hex-Ziffer
  1367.  
  1368. tolower
  1369.  
  1370. int tolower(int c)
  1371.  
  1372.     Die Funktion wandelt das Zeichen "c", sofern es sich 
  1373. dabei um einen Großbuchstaben handelt, in den 
  1374. entsprechenden Kleinbuchstaben um. Andernfalls wird das 
  1375. Argument unverändert zurückgegeben. Die Funktion 
  1376. entspricht dabei in etwa der Fallunterscheidung
  1377.  
  1378.         if (c >= «A« && c <= «Z«)
  1379.             return c+(«a«-«A«);
  1380.         else
  1381.             return c;
  1382.  
  1383.     Auch hier werden Umlaute leider nicht berücksichtigt.
  1384.  
  1385. toupper
  1386.  
  1387. int toupper(int c)
  1388.  
  1389.     Analog zu "tolower" werden hier Kleinbuchstaben in 
  1390. Großbuchstaben umgewandelt und andere Zeichen unverändert 
  1391. belassen.
  1392.  
  1393. which_xdigit [M]
  1394.  
  1395. int which_xdigit(char c)
  1396.  
  1397.     Wenn der Parameter "c" eine hexadezimale Ziffer ist, wird 
  1398. der zugehörige numerische Wert zurückgegeben, andernfalls 
  1399. "-1". Beispiele:
  1400.  
  1401.     which_xdigit(«7«)    =    7
  1402.     which_xdigit(«b«)    =    11
  1403.     which_xdigit(«C«)    =    12
  1404.     which_xdigit(«+«)    =    -1
  1405.  
  1406. 1.5 Fehlernummern: <errno.h>
  1407. Während der Laufzeit eines Programms kann so einiges 
  1408. schiefgehen - ein guter Programmierer geht immer davon 
  1409. aus, daß alles schief geht, was irgendwie schiefgehen 
  1410. kann. Die Analyse von Laufzeitfehlern wird mit den 
  1411. Definitionen der Datei <errno.h> ein wenig erleichtert.
  1412.  
  1413. errno
  1414.  
  1415. extern int errno
  1416.  
  1417.     In dieser globalen Variablen legen viele 
  1418. Standard-Funktionen in Falle eines Falles eine 
  1419. Fehlernummer ab. Beispielsweise wird hier die 
  1420. entsprechende DOS-Fehlernummer zugewiesen, wenn bei 
  1421. "fopen" keine Datei geöffnet werden konnte. Vor solchen 
  1422. kritischen Operationen sollte man deshalb "errno" auf Null 
  1423. setzen.
  1424.  
  1425. ERANGE
  1426.  
  1427. #define ERANGE 1000
  1428.  
  1429.     Diese Fehlernummer wird "errno" zugewiesen, wenn bei 
  1430. einer Funktion ein Wertebereich überschritten wurde.
  1431.  
  1432. EUSRBRK [M]
  1433.  
  1434. #define EUSRBRK 900
  1435.  
  1436.     Diese Konstante gibt den Rückgabewert eines Programms an, 
  1437. wenn es vom Benutzer abgebrochen wurde. Obwohl die 
  1438. Konstante in <errno.h> definiert wird, wird dieser Wert 
  1439. dabei nicht wirklich an "errno" zugewiesen und kann 
  1440. folglich auch nicht abgefragt werden. Vielmehr wird diese 
  1441. Konstante definiert, damit man mit einer Anweisung wie 
  1442. "exit(EUSRBRK)" ein derartiges Programmende simulieren 
  1443. kann.
  1444.  
  1445.  
  1446. EASSERT [M]
  1447.  
  1448. #define EASSERT 990
  1449.  
  1450.     Genau wie "EUSRBRK" ist dies kein Wert, den "errno" 
  1451. annimmt, sondern der Rückgabewert eines Programms, und 
  1452. zwar dann, wenn bei einem "assert"-Makro ein Fehler 
  1453. entdeckt wird.
  1454.  
  1455. EFREEMEM [M]
  1456.  
  1457. #define EFREEMEM 996
  1458.  
  1459.     Auch dies ist ein Rückgabewert und keine wirkliche 
  1460. Fehlernummer. Mit diesem Wert bricht ein Programm ab, wenn 
  1461. bei "free" bzw. "delete" ein ungültiger Speicherbereich 
  1462. freigegeben werden soll.
  1463.  
  1464. ENONUM [M]
  1465.  
  1466. #define ENONUM 1001
  1467.  
  1468.     Dieser Fehlercode wird von Funktionen wie "atoi" oder 
  1469. "strtod" gesetzt, wenn ein String keine gültige 
  1470. Zahldarstellung ist.
  1471.  
  1472. ENOMEM [M]
  1473.  
  1474. #define ENOMEM 1002
  1475.  
  1476.     "new" und die "malloc"-Funktion setzen diese 
  1477. Fehlernummer, wenn kein Speicher reserviert werden konnte.
  1478.  
  1479.  
  1480. 1.6 Ganzzahlige Grenzwerte: <limits.h>
  1481. Jede Implementierung kann mehr oder weniger frei 
  1482. festlegen, welchen Umfang die einzelnen Datentypen haben. 
  1483. In der Datei <limits.h> werden Konstanten definiert, die 
  1484. die spezifischen Daten eines C-Systems angeben und so 
  1485. standard-gemäße Programmierung erleichtern.
  1486.  
  1487. CHAR_BIT
  1488.  
  1489. #define CHAR_BIT 8
  1490.  
  1491.     gibt die Anzahl der Bits in einem "char" an.
  1492.  
  1493. CHAR_MAX, CHAR_MIN, SCHAR_MAX, SCHAR_MIN, SHRT_MAX
  1494. SHRT_MIN, INT_MAX, INT_MIN, LONG_MAX, LONG_MIN,
  1495. LONGLONG_MAX, LONGLONG_MIN
  1496.  
  1497. #define CHAR_MAX       127
  1498. #define CHAR_MIN       (-128)
  1499. #define SCHAR_MAX      127
  1500. #define SCHAR_MIN      (-128)
  1501. #define SHRT_MAX       0x7fff
  1502. #define SHRT_MIN       (-0x8000)
  1503. #define INT_MAX        0x7fffffff
  1504. #define INT_MIN        (-0x80000000)
  1505. #define LONG_MAX       0x7fffffff
  1506. #define LONG_MIN       (-0x80000000)
  1507. #define LONGLONG_MAX   0x7fffffffffffffffLL
  1508. #define LONGLONG_MIN   (-0x8000000000000000LL)
  1509.  
  1510.     Zu jedem vorzeichenbehafteten Datentyp existieren je zwei 
  1511. Konstanten, die den minimalen bzw. maximalen Wert dieses 
  1512. Typs angeben. Dementsprechend enden die Namen dieser 
  1513. Konstanten auf "_MIN" oder "_MAX" und beginnen je nach Typ 
  1514. mit "CHAR", "SCHAR", "SHRT", "INT", "LONG" oder "LONGLONG".
  1515.  
  1516.  
  1517. UCHAR_MAX, USHRT_MAX, UINT_MAX, ULONG_MAX,
  1518. ULONGLONG_MAX
  1519.  
  1520. #define    UCHAR_MAX    255
  1521. #define    USHRT_MAX    65535
  1522. #define    UINT_MAX    0xffffffffU
  1523. #define    ULONG_MAX    0xffffffffU
  1524. #define    ULONGLONG_MAX    0xffffffffffffffffULL
  1525.  
  1526.     Bei den vorzeichenbehafteten ganzzahligen Datentypen ist 
  1527. naturgemäß stets Null der kleinste darstellbare Wert. 
  1528. Deshalb existiert für diese Typen lediglich jeweils eine 
  1529. Konstante, die den höchsten Wert des Datentyps darstellt.
  1530.  
  1531. 1.7 Mathematische Funktionen: <math.h>
  1532. 1.7.1 Umwandlung von Zahlen in Zeichenketten
  1533.  
  1534. PARAMETER_BASE, PARAMETER_DIGITS [M]
  1535.  
  1536. #ifdef __cplusplus
  1537. #define PARAMETER_BASE short=10
  1538. #define PARAMETER_DIGITS short=0
  1539. #else
  1540. #define PARAMETER_BASE short
  1541. #define PARAMETER_DIGITS short
  1542. #endif
  1543.  
  1544.     Die nachfolgend beschriebenen Funktionen sind allesamt 
  1545. Spezialitätenvon MaxonC++ und wurden durch 
  1546. Default-Argumente etwas komfortabler gemacht. Da ANSI C 
  1547. aber keine Default-Argumente kennt, werden in den 
  1548. Parameterlisten diese beiden Makros benutzt. In C++ kann 
  1549. man also das jeweilige Argument weglassen, in C muß man es 
  1550. setzen. Übrigens werden die Makronamen am Ende von 
  1551. <math.h> mit "#undef" wieder gelöscht, so daß im weiteren 
  1552. keine Kollisionen auftreten.
  1553.  
  1554.  
  1555. inttostr, uinttostr, vlongtostr, uvlongtostr [M]
  1556.  
  1557. char *inttostr (int i, char s[ ], PARAMETER_BASE)
  1558. char *uinttostr (unsigned u, char s[ ], PARAMETER_BASE)
  1559. char *vlongtostr (long long ll, char s[ ], PARAMETER_BASE)
  1560. char *uvlongtostr (unsigned long long ull, char s[ ], 
  1561. PARAMETER_BASE)
  1562.  
  1563.     Diese vier Funktionen wandeln ihr jeweils erstes Argument 
  1564. in eineZeichenkette um und legen das Ergebnis im String 
  1565. "s" ab. Der (in C++ optionale) dritte Parameter gibt die 
  1566. gewünschte Basis, eine Zahl von 2 bis 36, an, wobei 10 
  1567. Default-Wert ist. Die umgewandelte Zeichenkette wird 
  1568. natürlich mit einem Nullzeichen abgeschlossen und ein 
  1569. Zeiger auf "s" zurückgegeben. Sie als Programmierer sind 
  1570. selbst dafür verantwortlich, daß der String "s" lang genug 
  1571. für das Ergebnis ist.
  1572.  
  1573. doubletostr, floattostr [M]
  1574.  
  1575. char *floattostr (float f, char s[ ], PARAMETER_DIGITS)
  1576. char *doubletostr (double d, char s[ ], PARAMETER_DIGITS)
  1577.  
  1578.     Mit diesen beiden Funktionen können Sie bequem und ohne 
  1579. Benutzung von "sprintf" eine Fließkommazahl in eine 
  1580. Zeichenkette verwandeln. Das Ergebnis mit einem 
  1581. abschließenden Nullbyte wird dabei im String "s" abgelegt 
  1582. (der natürlich hinreichend lang sein sollte), und der 
  1583. letzte Parameter, für den im C++-Modus der Default-Wert 
  1584. Null definiert ist, gibt den Modus und die Ziffernanzahl 
  1585. an:
  1586.     Bei einer positiven Anzahl von Stellen entspricht diese 
  1587. der Zahl der Nachkommastellen:
  1588.  
  1589.         doubletostr(17.4, s, 5)
  1590.  
  1591.     liefert
  1592.     s = " 17.40000",
  1593.     während eine negative Anzahl die Gesamtzahl der 
  1594. Dezimalstellen bei Exponential-darstellung angibt:
  1595.  
  1596.         doubletostr(17.4, s, -5)
  1597.  
  1598.     führt zum Ergebnis
  1599.     s = " 1.7400e+001".
  1600.     und beim Argument "0" (bzw. dem Default-Argument) wird 
  1601. für Zahlen zwischen 10000 und 0.1 die Festpunktdarstellung 
  1602. mit der minimalen Anzahl von Nachkommastellen und sonst 
  1603. die Exponentialdarstellung gewählt.
  1604.     Im Gegensatz zu den zuvor beschriebenen ganzzahligen 
  1605. Formatierungsfunktionen wird bei "doubletostr" und 
  1606. "floattostr" positiven Zahlen ein Leerzeichen 
  1607. vorangestellt.
  1608.  
  1609. 1.7.2 Fließkomma-Berechnungen
  1610.  
  1611. sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, exp, 
  1612. log, log10, sqrt
  1613.  
  1614. double    sin (double x)
  1615. double    cos (double x)
  1616. double    tan (double x)
  1617. double    asin (double x)
  1618. double    acos (double x)
  1619. double    atan (double x)
  1620. double    sinh (double x)
  1621. double    cosh (double x)
  1622. double    tanh (double x)
  1623. double    exp (double x)
  1624. double    log (double x)
  1625. double    log10 (double x)
  1626. double    sqrt (double x)
  1627.  
  1628.     Diese Funktionen stellen die wichtigsten mathematischen 
  1629. Funktionen dar. Offensichtlich sind ihr Argument und 
  1630. Ergebnis jeweils "double"-Werte. Die Funktionen haben 
  1631. folgende (meist offensichtliche) Bedeutung:
  1632.  
  1633.     sin        Sinus
  1634.     cos        Cosinus
  1635.     tan        Tangens
  1636.     asin        sin^-1 für Argumente zwischen -1 und 1
  1637.     acos        cos^-1 für Argumente zwischen -1 und 1
  1638.     atan        tan^-1, Ergebnis zwischen -pi/2 und +pi/2
  1639.     sinh        Sinus Hyperbolicus
  1640.     cosh        Cosinus Hyperbolicus
  1641.     tanh        Tangens Hyperbolicus
  1642.     exp        Exponentialfunktion e^x
  1643.     log        Natürlicher Logarithmus
  1644.     log10        Logarithmus zur Basis 10
  1645.     sqrt        Quadratwurzel
  1646.  
  1647.     Bei den trigonometrichen Funktionen werden Winkel 
  1648. natürlich im Bogenmaß (Radian) angegeben. Ein Gradwinkel 
  1649. "w" läßt sich mit der Formel
  1650.         x = 3.14159265358979/180.0 * w
  1651.     in Bogenmaß umrechnen.
  1652.  
  1653. pow
  1654.  
  1655. double pow (double x, double y)
  1656.  
  1657.     Diese Funktion berechnet die Potenz x^y, wobei aber "x" 
  1658. positiv sein muß.
  1659.  
  1660. atan2
  1661.  
  1662. atan2(double x, double y)
  1663.  
  1664.     berechnet den Arcustangens von y/x, d. h. den Winkel, der 
  1665. zum Cosinus "x" und dem Sinus "y" gehört. Das Ergebnis ist 
  1666. aus [-pi, +pi], und die Funktion ist besonders dann 
  1667. praktisch, wenn man kartesische in Polarkoordinaten 
  1668. umrechnen will.
  1669.  
  1670. floor
  1671.  
  1672. floor(double x)
  1673.  
  1674.     Die Funktion "floor" rundet auf die nächstkleinere ganze 
  1675. Zahl ab (genaugenommen die größte ganze Zahl kleiner oder 
  1676. gleich x). Das Ergebnis ist nichtsdestotrotz ein "double"- 
  1677. und kein "int"-Wert.
  1678.  
  1679. ceil
  1680.  
  1681. double ceil(double x)
  1682.  
  1683.     Analog zu "floor" rundet "ceil" ihr Argument auf.
  1684.  
  1685. fabs
  1686.  
  1687. fabs(double x)
  1688.  
  1689.     "fabs" liefert den Betrag ihres Arguments "x".
  1690. ldexp
  1691.  
  1692. ldexp(double x,int n)
  1693.  
  1694.     Mit dieser Funktion erzeugt man aus einer Mantisse "x" 
  1695. und einem Binär-Exponenten "n" eine Fließkommazahl "x * 
  1696. 2^n". "ldexp" ist vor allem dann nützlich und auch 
  1697. ausgesprochen schnell, wenn man einen "double"-Wert mit 
  1698. einer Zweierpotenz multiplizieren will.
  1699.  
  1700. frexp
  1701.  
  1702. double frexp(double x ,int *expo)
  1703.  
  1704.     "frexp" ist das Gegenstück zu "ldexp", denn hier wird das 
  1705. Argument in eine normalisierte Mantisse im Bereich von 0.5 
  1706. bis 1 und einen Exponenten zur Basis 2 zerlegt. Die 
  1707. Mantisse wird als Funktionswert zurückgegeben, während der 
  1708. Exponent in "*expo" abgelegt wird.
  1709.  
  1710. modf
  1711.  
  1712. double modf(double x, double *dp)
  1713.  
  1714.     Die Zahl "x" wird in ihre Vor- und Nachkommastellen 
  1715. aufgeteilt. Die Nachkommastellen, also eine Zahl zwischen 
  1716. -1 und +1, sind das Resultat der Funktion, während der 
  1717. ganzzahlige Teil nach "*dp" geschrieben wird. Beide 
  1718. Ergebnisse haben das gleiche Vorzeichen wie "x".
  1719.  
  1720. fmod
  1721.  
  1722. double fmod(double x, double y)
  1723.  
  1724.     Diese Funktion sollte nicht mit "modf" verwechselt 
  1725. werden, sie berechnet den Rest, der bei einer 
  1726. Fließkommadivision "x/y" bei ganzzahligem Quotienten 
  1727. auftritt.
  1728.  
  1729. pwr10 [M]
  1730.  
  1731. double pwr10(int i)
  1732.  
  1733.     Für ganzzahlige "i" im Bereich von -308 bis +308 liefert 
  1734. "prw10" die Potenz 10^i, und zwar ziemlich schnell, denn 
  1735. die Werte werden dabei teilweise einer Tabelle entnommen.
  1736.  
  1737.  
  1738. expo10 [M]
  1739.  
  1740. int expo10(double x)
  1741.  
  1742.     Diese Funktion liefert die größte ganze Zahl "n", für die 
  1743. "prw10(n)" nicht größer als "x" ist, also den 
  1744. Exponententeil von "x". Nicht ganz zufällig sind "pwr10" 
  1745. und "expo10" Abfallprodukte der 
  1746. Stringkonvertierungsfunktionen von Fließkommazahlen.
  1747.  
  1748. fpwr10 [M]
  1749.  
  1750. float fpwr10(int i)
  1751.  
  1752.     "fpwr10" ist das "float"-Gegenstück zu "pwr10" und 
  1753. berechnet ebenfalls die Potenz "10^i", aber als 
  1754. "float"-Wert.
  1755.  
  1756. 1.8 Haarsträubende Sprünge: <setjmp.h>
  1757.  
  1758. setjmp, longjmp
  1759.  
  1760. int setjmp(jmp_buf buf)
  1761. void longjmp(jmp_buf buf, int num)
  1762.  
  1763.     Die normalen "goto"-Sprünge können nur innerhalb einer 
  1764. Funktion herumspringen, und das ist oft nicht genug. 
  1765. Manchmal muß man von einer Funktion in eine andere 
  1766. zurückspringen, z. B. wenn irgendwo in einer tief 
  1767. verschachtelten Reihe von Funktionsaufrufen ein Fehler 
  1768. auftritt und die Programmfunktion, aber nicht das ganze 
  1769. Programm abgebrochen werden soll. Es wäre dabei meist sehr 
  1770. umständlich, hinter jeden der zahllosen Funktionsaufrufe 
  1771. eine Abfrage der Art "Ist-ein-Fehler- 
  1772. aufgetreten-wenn-ja-dann-Ende" zu setzen. Deshalb gibt es 
  1773. die beiden Funktionen "setjmp" und "longjmp", mit denen 
  1774. man direkt aus einer Funktion in eine andere, höher 
  1775. gelegene zurückspringen kann.
  1776.     Man kann dabei keineswegs wild in irgendeine Funktion 
  1777. hineinspringen, denn dann wäre der Absturz nahezu 
  1778. garantiert. Vielmehr speichert "setjmp" die wichtigsten 
  1779. Daten eines Zustands, nämlich den Stackpointer, den 
  1780. Programmzähler und die übrigen Prozessorregister, in einem 
  1781. Puffer des Typs "jmp_buf" ab, und "longjmp" stellt eben 
  1782. diesen Zustand wieder her, aber nur dann, wenn die 
  1783. Funktion, in der "setjmp" aufgerufen wurde, bisher nicht 
  1784. beendet wurde.
  1785.     Der Ablauf ist also immer der folgende: In einer Funktion 
  1786. "f1" wird "setjmp" aufgerufen, und damit merkt sich das 
  1787. Programm haargenau die Position dieses "setjmp"-Aufrufs. 
  1788. Nun kann aus "f1" eine andere Funktion "f2" aufgerufen 
  1789. werden, welche möglicherweise wiederum irgendwann eine 
  1790. Funktion "f3" aufruft, in der ein Aufruf von "f4" 
  1791. stattfindet... Jedenfalls befindet das Programm sich 
  1792. irgendwann in einer Funktion "fx", und dann wird mit 
  1793. "longjmp" der abgespeicherte Zustand wiederhergestellt: 
  1794. Die Funktion "fx" wird beendet und alle ihre Daten sowie 
  1795. die der anderen Funktionen bis einschließlich "f2" werden 
  1796. vom Stack entfernt. Die Programmausführung wird in "f1" an 
  1797. genau der Stelle, an der das "setjmp" steht, fortgesetzt.
  1798.     Nach jedem "setjmp" sollte das Programm dann feststellen, 
  1799. was passiert ist: Wurde soeben "setjmp" ausgeführt und der 
  1800. Programmzustand abgespeichert, oder ist ein "longjmp" 
  1801. erfolgt? Im letzteren Fall befindet sich das Programm 
  1802. schließlich scheinbar auch direkt hinter dem Aufruf von 
  1803. "setjmp". Deshalb hat "setjmp" einen Ergebniswert, der im 
  1804. Prinzip immer Null ist, und der Funktion "longjmp" kann 
  1805. ein numerisches Argument übergeben werden. Beim 
  1806. "longjmp"-Sprung wird dem Programm dann vorgegaukelt, 
  1807. "setjmp" habe dieses Argument als Ergebnis geliefert.
  1808.     Am besten wird die Sache wohl an einem Beispiel deutlich. 
  1809. Eine typische Anwendung von "setjmp" und "longjmp" sieht 
  1810. so aus:
  1811.         #include <setjmp.h>
  1812.  
  1813.         jmp_buf Ausstieg;
  1814.  
  1815.         void f2()
  1816.         {
  1817.             printf("Funktion f2:\n");
  1818.  
  1819.             longjmp(Ausstieg,17);
  1820.  
  1821.             printf("PANIC\n");    // Diese Stelle wird nie erreicht.
  1822.         }
  1823.  
  1824.         void f1()
  1825.         {
  1826.             if(setjmp(Ausstieg) == 0)
  1827.             // Ergebnis 0: Es wurde wirklich bloß der Zustand 
  1828. gespeichert
  1829.             {
  1830.                 printf("Jump gesetzt.\n");
  1831.                 f2();
  1832.                 // Diese Stelle wird nur erreicht,
  1833.                 // wenn kein "longjmp" gemacht wird:
  1834.                 printf("DOUBLE PANIC\n");
  1835.             }
  1836.             else
  1837.                 // Ergebnis 17: longjmp wurde ausgeführt
  1838.                 printf("Jump ausgeführt.\n");
  1839.         }
  1840.  
  1841.  
  1842.     Die Funktion "f1" macht dabei folgende Ausgabe:
  1843.     Jump gesetzt.
  1844.     Funktion f2:
  1845.     Jump ausgeführt.
  1846.     "jmp_buf" ist stets ein Vektortyp, weshalb bei "setjmp" 
  1847. kein Adressoperator "&" vor das Argument gesetzt werden 
  1848. muß. Ihnen dürfte (oder sollte) klar sein, daß diese 
  1849. Funktion in der Regel ziemlich hanebüchen implementiert 
  1850. wird. Deshalb darf man "setjmp" nur in ganz bestimmten 
  1851. Zusammenhängen benutzen:
  1852.     Man darf auf "setjmp" unäre Operatoren, z. B. "-" oder 
  1853. "!", anwenden.
  1854.     Das Ergebnis kann mit den Operatoren "==", "!=", "<", 
  1855. ">", "<=" oder ">=" mit einem konstanten numerischen 
  1856. Ausdruck verglichen werden.
  1857.     Der Ausdruck kann "einfach so" als Anweisung stehen oder 
  1858. bei "if", "while", "do" oder "switch" als Bedingung 
  1859. verwendet werden.
  1860.     Ein Ausdruck wie
  1861.  
  1862.         printf("Ergebnis: %d\n", setjmp(x))
  1863.  
  1864.     würde also unter den meisten Implementierungen 
  1865. (einschließlich MaxonC++) beim anschließenden "longjmp" zu 
  1866. einem gnadenlosen Absturz führen. Selbst ein scheinbar so 
  1867. harmloses Konstrukt wie
  1868.         int i;
  1869.         i = setjmp(x);
  1870.         if (i == 0)
  1871.         { usw.
  1872.  
  1873.     ist nicht zulässig (auch wenn es bei MaxonC++ zufällig 
  1874. klappt).
  1875.     Es gibt noch einige andere Einschränkungen: Da "longjmp" 
  1876. ein echtes Low-Level-Konstrukt ist, das den Compiler 
  1877. praktisch heimtückisch überlistet, werden zwar die 
  1878. automatischen Variablen der solchermaßen "abgewürgten" 
  1879. Funktionen vom Stack entfernt, aber keine Destruktoren 
  1880. aufgerufen. Nach der Rückkehr durch "longjmp" müssen Sie 
  1881. auch damit rechnen, daß die Optimierungen des Compilers 
  1882. Ärger machen und automatische Variablen jener Funktion, 
  1883. die nicht als "volatile" deklariert sind, undefinierte 
  1884. Werte haben.
  1885.  
  1886.  
  1887. jmp_buf
  1888.  
  1889. typedef int jmp_buf[_JMP_BUF_SIZE]
  1890.  
  1891.     Dieser Datentyp repräsentiert einen geeigneten Puffer, in 
  1892. dem "setjmp" einen Programmzustand abspeichern kann.
  1893.  
  1894. JMP_BUF_SIZE [M]
  1895.  
  1896. #define _JMP_BUF_SIZE 16
  1897.  
  1898.     Eine kleine, unbedeutende Hilfskonstante, die die Größe 
  1899. des Vektortyps "jmp_buf" angibt.
  1900.  
  1901. 1.9 Signale und Ereignisse: <signal.h>
  1902.  
  1903. signal
  1904.  
  1905. void (*signal(int sig, void(*f)(int)))(int)
  1906.  
  1907.     oder besser:
  1908. typedef void (*P2F)(int)
  1909. P2F signal (int sig, P2F f)
  1910.  
  1911.     Die Funktion "signal" setzt eine Funktion, die aufgerufen 
  1912. werden soll, wenn ein bestimmtes Signal "sig" eintrifft. 
  1913. In der vorliegenden Version von MaxonC++ ist die Funktion 
  1914. "signal" weitgehend Makulatur, denn bisher wird ein Signal 
  1915. ausschließlich vom Programm selbst durch die Funktion 
  1916. "raise" gesendet. Der Parameter "sig" gibt die jeweilige 
  1917. Signalnummer - in der Regel eines der im folgenden 
  1918. beschriebenen Makros - an, und "f" ist ein Zeiger auf eine 
  1919. Funktion, die ein "int" als Argument erhält und kein 
  1920. Ergebnis (also "void") liefert. Das Ergebnis von "signal" 
  1921. ist ein Zeiger auf die Funktion, die vorher als 
  1922. Signal-Handler gesetzt war.
  1923.     Anschließend wird die Funktion "f" stets beim Eintreffen 
  1924. eines Signals "sig" aufgerufen und erhält dabei als 
  1925. Argument die Signalnummer, so daß eine Funktion durchaus 
  1926. als Handler für mehrere Signale verwendet werden kann.
  1927.     Anstelle eines Zeigers auf eine Funktion kann auch eins 
  1928. der unten beschriebenen Makros "SIG_IGN", "SIG_DFL" oder 
  1929. "SIG_ERR" verwendet werden.
  1930.  
  1931.  
  1932. raise
  1933.  
  1934. int raise(int sig)
  1935.  
  1936.     Die Funktion "raise" sendet das Signal "sig" und löst so 
  1937. den Aufruf des entsprechenden Handlers aus.
  1938.  
  1939. SIGTERM, SIGABRT, SIGPFE, SIGILL, SIGINT, SIGSEGV
  1940.  
  1941. #define    SIGTERM    0    // Normales Programmende
  1942. #define    SIGABRT    1    // Anormales Programmende wie bei "abort"
  1943. #define    SIGFPE    2    // Arithmetikfehler
  1944. #define    SIGILL    3    // Illegale Prozessor-Anweisung
  1945. #define    SIGINT    4    // Software-Interrupt
  1946. #define    SIGSEGV    5    // Segmentverletzung bei Speicherzugriff
  1947.  
  1948.     Dies sind die sechs Standard-Signalnummern und damit die 
  1949. einzigen wirklich legalen Argumente für "signal" und 
  1950. "raise". Eine Implementierung darf aber auch noch 
  1951. zusätzliche eigene Signale haben.
  1952.  
  1953. SIG_IGN
  1954.  
  1955. #define SIG_IGN ((void(*)(int))0)
  1956.  
  1957.     Wird bei "signal" als Handlerfunktion "SIG_IGN" 
  1958. angegeben, so wird das entsprechede Signal in Zukunft 
  1959. ignoriert.
  1960.  
  1961. SIG_DFL
  1962.  
  1963. #define SIG_DFL ((void(*)(int))1)
  1964.  
  1965.     Diese Pseudo-Handlerfunktion stellt als Argument bei 
  1966. "signal" den jeweiligen Default-Handler dar.
  1967.  
  1968. SIG_ERR
  1969.  
  1970. #define SIG_ERR ((void(*)(int))-1)
  1971.  
  1972.     Die Funktion "signal" liefert das Ergebnis "SIG_ERR", 
  1973. wenn irgendein Fehler aufgetreten ist, z. B. die Argumente 
  1974. illegal waren.
  1975.  
  1976. sig_atomic_t
  1977.  
  1978. typedef int sig_atomic_t
  1979.  
  1980.     Für echte Signal-Freaks gibt es den ganzzahligen Datentyp 
  1981. "sig_atomic_t", der zur Kommunikation zwischen Programm 
  1982. und Handler benutzt werden kann. Die "besondere" 
  1983. Eigenschaft dieses Datentyps ist, daß ein Zugriff auf eine 
  1984. solche Variable eine unteilbare Operation ist, d. h. nicht 
  1985. unterbrochen werden kann. Wenn man einer Variablen dieses 
  1986. Typs einen Wert zuweist, kann man darauf vertrauen, daß 
  1987. ein währenddessen eintreffendes Signal entweder vor oder 
  1988. nach dieser Operation ausgeführt wird und nicht etwa 
  1989. mittendrin, wenn die Variable so etwas wie einen 
  1990. Zwischenwert hat.
  1991.     Oder drücken wir es einmal so aus: Eine "long 
  1992. long"-Variable besteht unter MaxonC++ aus zwei Langworten, 
  1993. die bei einer Wertzuweisung nacheinander geschrieben 
  1994. werden. Hier könnte es durchaus vorkommen, daß ein 
  1995. Signal-Handler genau dann aufgerufen wird, wenn erst eines 
  1996. der beiden Langworte geschrieben ist. Der Wert der 
  1997. Variablen wäre dann während der Ausführung des Handlers 
  1998. irgendwie eine undefinierte Mischung aus dem alten und dem 
  1999. neuen Wert. Wenn man also in einer globalen Variablen 
  2000. Parameter an einen Handler übergeben möchte, sollte man 
  2001. dafür ausschließlich den Datentyp "sig_atomic_t" benutzen.
  2002.  
  2003.  
  2004. 1.10 Variable Argumentlisten: <stdarg.h>
  2005.  
  2006. va_list
  2007.  
  2008. typedef unsigned int va_list
  2009.  
  2010.     Funktionen wie "printf" und "scanf" haben eine 
  2011. Parameterliste, in der jeweils nur die ersten Parameter 
  2012. einen Namen und Typ haben und anschließend beliebig viele 
  2013. weitere Argumente erlaubt sind. Syntaktisch wird dies in 
  2014. C++ durch die Ellipse "..." am Ende der Parameterliste 
  2015. deklariert, und man kann dieses Feature auch in 
  2016. selbstgeschriebenen Funktionen verwenden. Nun wird sich 
  2017. der geneigte Leser vielleicht fragen, wie eine Funktion 
  2018. denn solche namenlose Parameter mit nahezu beliebiger 
  2019. Anzahl und unterschiedlichsten Typen auswerten kann. Genau 
  2020. dabei hilft die Includedatei "<stdarg.h>", die einige 
  2021. Makros deklariert, mit denen man Stack-Argumente 
  2022. gleichermaßen komfortabel und portabel auswerten kann.
  2023.     Das Prinzip beruht darauf, daß ein Zeiger hinter den 
  2024. letzten normal deklarierten Parameter gesetzt wird und 
  2025. dann der Reihe nach die restliche Argumentliste 
  2026. durchläuft. Dieser "Zeiger" wird repräsentiert durch eine 
  2027. Variable des Typs "va_list".
  2028.  
  2029. va_start
  2030.  
  2031. #define va_start(AP,LASTARG) (AP)=(unsigned int)(&LASTARG) 
  2032. \ +sizeof(LASTARG)
  2033.  
  2034.     Ein Argumentlisten-Zeiger des Typs "va_list" wird 
  2035. normalerweise initialisiert, indem er auf die erste 
  2036. Adresse hinter dem letzten Parameter gesetzt wird, also 
  2037. auf genau die Speicheradresse, an der die formal 
  2038. unbekannten, restlichen Argumente anfangen. Dazu dient das 
  2039. Makro "va_start", z. B. so:
  2040.         void fun(const char *format...)
  2041.         {
  2042.             va_list v;
  2043.             va_start(v, format);
  2044.  
  2045.             // usw.
  2046.         }
  2047.  
  2048. va_arg
  2049.  
  2050. #define va_arg(AP,TYPE) ((AP)+=sizeof(TYPE), \ 
  2051. sizeof(TYPE)>1 ? ((AP)=(AP)+1&(-2)):(AP), \ 
  2052. ((TYPE*)AP)[-1])
  2053.  
  2054.     Das Makro "va_arg" mit seiner ziemlich wüsten Definition 
  2055. ist in seiner Anwendung um so einfacher: Ein Aufruf der 
  2056. Form
  2057.         x = va_arg(vp, TYPE);
  2058.     
  2059.     liest das nächste Argument des Typs "TYPE" aus der 
  2060. variablen Argumentliste, liefert es als Ergebnis und setzt 
  2061. nebenbei den Argumentzeiger "vp" entsprechend weiter. Wenn 
  2062. man also die auftretenden Datentypen kennt (bei "printf" 
  2063. gibt man diese ja im Formatstring an), kann man mit einer 
  2064. Folge von "va_arg"-Aufrufen nacheinander die Argumente 
  2065. lesen.
  2066.     Beachten Sie aber, daß "kurze" ganzzahlige Typen (short, 
  2067. char) bei dieser  Art der Wertübergabe automatisch nach 
  2068. "int" sowie "float" nach "double" umgewandelt werden. 
  2069. Deshalb ist z. B. "va_arg(x, unsigned short)" generell 
  2070. unsinnig und ist durch "va_arg(x, unsigned int)" zu 
  2071. ersetzen.
  2072.  
  2073.  
  2074. va_end
  2075.  
  2076. #define va_end(AP)
  2077.  
  2078.     Bei einigen Implementierungen kann die Auswertung 
  2079. variabler Argumentlisten ein ziemicher Akt sein, und 
  2080. deshalb gibt es das Makro "va_end", mit dem man immer eine 
  2081. Argumentauswertung beenden sollte und das bei Bedarf 
  2082. irgendwelche Aufräumarbeiten durchführt. Bei MaxonC++ ist 
  2083. "va_end" ein leeres Makro, aber trotzdem sollte man es nie 
  2084. vergessen.
  2085.     Zum Abschluß ein zusammenhängendes Beispiel für die 
  2086. Auswertung variabler Argumentlisten. Der Einfachheit 
  2087. halber ist die Argumentliste hier überhaupt nicht 
  2088. variabel, sondern es wird stets erwartet, daß ein "int"-, 
  2089. ein "double"- und ein "char"-Argument folgen. Trotzdem 
  2090. sollte das Prinzip klar werden:
  2091.  
  2092.         #include <stdarg.h>
  2093.         #include <stdio.h>
  2094.  
  2095.         void fun(const char *format...)
  2096.         {
  2097.             va_list v;
  2098.             int i;
  2099.             double d;
  2100.             char c;
  2101.  
  2102.             va_start(v, format);  // initialisieren mit letztem 
  2103. bekannten
  2104.             // Parameter
  2105.  
  2106.             // die drei Argumente werden der Reihe nach gele    sen:
  2107.             i = va_arg(v, int);
  2108.             d = va_arg(v, double);
  2109.             c = (char) va_arg(v, int); // Auch chars werden als 
  2110. "int"
  2111.                         // Übergeben
  2112.  
  2113.             // der Ordnung halber aufräumen:
  2114.             va_end(v);
  2115.  
  2116.             printf("%s: %i , %g , %c\n", format, i, d, c);
  2117.         }
  2118.  
  2119.         void main()
  2120.         {
  2121.             fun("Test", 42, 47.11, «x«);
  2122.         }
  2123.  
  2124.  
  2125. 1.11 Implementationsabhängige Definitionen: <stddef.h>
  2126.  
  2127. NULL
  2128.  
  2129. #define NULL 0
  2130.  
  2131.     Die allgemein beliebte und geschätzte Konstante "NULL" 
  2132. wird auch in "<stddef.h>" deklariert.
  2133.  
  2134. offsetof
  2135.  
  2136. #define offsetof(s,m) ((unsigned)&((s*)NULL)->m)
  2137.  
  2138.     In ANSI C gibt es keine Pointer auf Member. Als die 
  2139. C-Programmierer daraufhin neidisch nach C++ schielten, 
  2140. kamen sie offensichtlich auf die Idee, dieses Feature in C 
  2141. zu simulieren, indem sie den Offset eines Members 
  2142. innerhalb einer Struktur berechnen. Mit dem Makro 
  2143. "offsetof" wird dies erheblich erleichtert: 
  2144. "offsetof(s,m)" liefert den Offset (in Bytes) des Members 
  2145. "m" in der Klasse oder Struktur "s".
  2146.  
  2147. size_t
  2148.  
  2149. typedef unsigned size_t
  2150.  
  2151.     "size_t" wird nicht nur in "<stdlib.h>" und "<stdio.h>", 
  2152. sondern auch in "stddef.h" definiert und stellt den Typen 
  2153. dar, den das Ergebnis von "sizeof" in einer bestimmten 
  2154. Implementation hat.
  2155.  
  2156. ptrdiff_t
  2157.  
  2158. typedef int ptrdiff_t
  2159.  
  2160.     Subtrahiert man zwei Zeiger gleichen Typs voneinander, so 
  2161. ist das Ergebnis bekanntlich ein ganzzahliger Wert, der 
  2162. die Anzahl der Vektorelemente zwischen diesen Zeigern 
  2163. angibt. Nun kann der Typ dieser Differenz durchaus 
  2164. implementationsabhängig sein: Bei einigen Compilern muß 
  2165. eine Adressdistanz als "long int" ausgedrückt werden, bei 
  2166. anderen (wie MaxonC++) reicht auch ein "int". Deshalb gibt 
  2167. es für diesen Typ den standardisierten Namen "ptrdiff_t".
  2168.  
  2169.  
  2170. wchar_t
  2171.  
  2172. typedef int wchar_t
  2173.  
  2174.     Noch eine Wiederholung: Der Name "wchar_t" bezeichnet den 
  2175. Datentyp von langen Zeichenkonstanten.
  2176.  
  2177. 1.12 Zeichenketten und Speicherverwaltung: <string.h>
  2178.  
  2179. strcpy
  2180.  
  2181. char *strcpy (char *s1, const char *s2)
  2182.  
  2183.     Das Vektorkonzept von ANSI C ist bekanntlich "far beyond 
  2184. repair" und hat unter anderem zur Folge, daß man Strings 
  2185. nicht mit einem einfachen "=" zuweisen kann. Deshalb gibt 
  2186. es die überaus nützliche Funktion "strcpy", die einen 
  2187. String "s2", der mit einem Nullbyte enden sollte, in eine 
  2188. Stringvariable "s1" kopiert. Das Ergebnis ist undefiniert, 
  2189. wenn die beiden Strings sich überlappen, und wie 
  2190. eigentlich immer haben Sie höchstpersönlich darüber zu 
  2191. wachen, daß die Zielvariable für den String "s2" lang 
  2192. genug ist. Das Ergebnis von "strcpy" ist der Zeiger "s1".
  2193.  
  2194. strncpy
  2195.  
  2196. char *strncpy(char *s1, const char *s1, size_t n)
  2197.  
  2198.     Die sicherheitsbetonte Variante von "strcpy" kopiert 
  2199. maximal "n" Zeichen aus "s2" nach "s1" und füllt den Rest 
  2200. mit Nullzeichen auf.
  2201.  
  2202. strcat
  2203.  
  2204. char *strcat (char *s1, const char *s2)
  2205.  
  2206.     In diesem Fall heißt "cat" nicht "Katze", sondern ist 
  2207. eine Verbalhornung von "concat" oder auf Deutsch 
  2208. "konkatinieren" - man kann auch "aneinanderhängen" dazu 
  2209. sagen. Die Funktion sucht sich das Ende des Zeichenvektors 
  2210. "s1" (am obligatorischen Nullbyte unschwer zu erkennen) 
  2211. und kopiert den String "s2" genau dorthin, wodurch die 
  2212. beiden Strings zusammengehängt werden. Auch hier ist es 
  2213. der Sorgfalt und Umsicht des Programmierers anheim 
  2214. gestellt, dafür zu sorgen, daß im String "s1" auch noch 
  2215. genug Platz ist. Der Rückgabewert ist wieder einmal ein 
  2216. Zeiger auf das Ergebnis, also "s1".
  2217. strncat
  2218.  
  2219. char *strncat(char *s1, const char *s2, size_t n)
  2220.  
  2221.     Genau wie bei "strcat" wird auch hier der String "s2" an 
  2222. den Inhalt des Zeichenvektors "s1" angehänht, aber hier 
  2223. werden maximal "n" Zeichen kopiert.
  2224.  
  2225. strcmp
  2226.  
  2227. int strcmp (const char *s1, const char *s2)
  2228.  
  2229.     Diese Funktion vergleicht die beiden Zeichenketten "s1" 
  2230. und "s2" und liefert:
  2231.     einen negativen Wert, wenn s1 < s2,
  2232.     Null, falls s1 == s2,
  2233.     eine positives Ergebnis, sofern s1 > s2.
  2234.     Natürlich werden hier wirklich die Zeichen des Strings 
  2235. verglichen und nicht etwa die Adressen, wie es ja bei 
  2236. gewöhnlichen Stringvergleichen der Fall ist.
  2237.  
  2238. strncmp
  2239.  
  2240. int strncmp(const char *s1, const char *s2, size_t n)
  2241.  
  2242.     "strncmp" entspricht "strcmp", vergleicht aber maximal 
  2243. die ersten "n" Zeichen, oder auch weniger, wenn eher auf 
  2244. ein Nullzeichen und damit das Stringende gestoßen wird.
  2245.  
  2246. stricmp [M]
  2247.  
  2248. int stricmp(const char *s1, const char *s2)
  2249.  
  2250.     Diese Funktion vergleicht die Zeichenketten "s1" und "s2" 
  2251. genau wie "strcmp", wandelt aber zuerst alle Klein- in 
  2252. Großbuchstaben um, bevor zwei Zeichen verglichen werden. 
  2253. Diese Umwandlung geschieht natürlich nur intern, so daß es 
  2254. keinen Seiteneffekt auf die Strings "s1" und "s2" gibt. 
  2255. Beispielsweise liefert "stricmp("Test", "TEST")" Null.
  2256.  
  2257.  
  2258. strlwr [M]
  2259.  
  2260. char *strlwr(char *s)
  2261.  
  2262.     In der durch ein Nullzeichen abgeschlossenen Zeichenkette 
  2263. "s" werden alle Großbuchstaben durch Kleinbuchstaben 
  2264. ersetzt. Ein Zeiger auf den solchermaßen veränderten 
  2265. String wird zurückgegeben.
  2266.  
  2267. strupr [M]
  2268.  
  2269. char *strupr(char *s)
  2270.  
  2271.     funktioniert wie "strlwr", wandelt aber Klein- in 
  2272. Großbuschtaben um.
  2273.  
  2274. strchr
  2275.  
  2276. char *strchr (const char *s, int c)
  2277.  
  2278.     Die Funktion sucht das erste Zeichen "c" im String "s" 
  2279. und liefert einen Zeiger darauf. Sollte in "s" kein "c" 
  2280. vorkommen, ist das Ergebnis Null.
  2281.  
  2282. strrchr
  2283.  
  2284. char *strrchr(const char *s, int c)
  2285.  
  2286.     leifert analog zu "strchr" einen Zeiger auf das letzte 
  2287. "c" in "s" oder Null, falls es so etwas nicht gibt.
  2288.  
  2289. strspn
  2290.  
  2291. size_t strspn (const char *s, const char *c)
  2292.  
  2293.     liefert die Anzahl der Zeichen am Anfang von "s", die 
  2294. alle auch in "c" vorkommen, z. B.
  2295.         strspn("caddy", "abcd") == 4
  2296.  
  2297.  
  2298. strcspn
  2299.  
  2300. size_t strcspn(const char *s, const char *c)
  2301.  
  2302.     ermittelt die Anzahl der Zeichen am Anfang von "s", die 
  2303. allesamt nicht im String "c" vorkommen.
  2304.  
  2305. strpbrk
  2306.  
  2307. char *strpbrk(const char *s, const char *c)
  2308.  
  2309.     ist eine Art erweiterte Version von "strchr" und liefert 
  2310. einen Zeiger auf die erste Stelle in "s", an der irgendein 
  2311. Zeichen aus "c" vorkommt.
  2312.  
  2313. strstr
  2314.  
  2315. char *strstr(const char *s1, const char *s2)
  2316.  
  2317.     Diese Funktion sucht die komplette Zeichenkette "s2" im 
  2318. String "s1" und liefert in gewohnter Manier einen Zeiger 
  2319. auf ihr erstes Auftreten oder Null.
  2320.  
  2321. strlen
  2322.  
  2323. size_t strlen(const char *s)
  2324.  
  2325.     liefert die Länge des Strings "s", wobei das Nullzeichen 
  2326. am Ende nicht mitgerechnet wird.
  2327.  
  2328. strerror
  2329.  
  2330. char *strerror(int n)
  2331.  
  2332.     liefert die Fehlermeldung zur Fehlernummer "n", also im 
  2333. Wesentlichen das, was "perror" ausgibt.
  2334.  
  2335.  
  2336. strtok
  2337.  
  2338. char *strtok(char *s, const char *c)
  2339.  
  2340.     Mit der Funktion "strtok" kann man eine Zeichenkette "s" 
  2341. in eine Folge von Zeichenketten, die jeweils durch Zeichen 
  2342. aus "c" begrenzt sind, zerlegen. Beim ersten Aufruf ist 
  2343. für "s" ein Zeiger auf den Anfang der Zeichenkette zu 
  2344. setzen, bei allen weiteren ist hier "Null" zu setzen. Die 
  2345. Funktion sucht jeweils die erste Position im String, an 
  2346. der ein Zeichen aus "c" auftritt, setzt an diese Stelle 
  2347. ein â\0" und gibt einen Zeiger auf den Anfang dieses 
  2348. Teilstrings zurück. Dabei merkt sie sich die Position, an 
  2349. der das Zeichen aus "c" gefunden und das Nullzeichen 
  2350. gesetzt wurde, und sucht beim nächsten Aufruf, sofern als 
  2351. erstes Argument Null übergeben wird, von dieser Stelle 
  2352. weiter.
  2353.     Wenn auf diese Weise der gesamte String verhackstückt 
  2354. wurde und kein Zeichen aus "c" mehr gefunden wurde, 
  2355. liefert "strtok" das Ergebnis Null.
  2356.     Der sittliche Nährwert dieser Funktion liegt darin, eine 
  2357. Zeichenfolge "s" in eine Folge von Token, die durch 
  2358. Trennzeichen aus "c" separiert werden, zu zerbröseln. 
  2359. Beispielsweise zerlegt das folgende Programm einen String 
  2360. in Worte, wobei eine Zeichenfolge, die keine Leerzeichen 
  2361. oder Zeilentrenner enthält, als Wort betrachtet wird:
  2362.         #include <string.h>
  2363.         #include <stdio.h>
  2364.  
  2365.         void main()
  2366.         {
  2367.             char s[ ] = "Alles Seiende entsteht ohne Grund,\nsetzt
  2368.              sich aus Schwäche fort und stirbt durch Zufall.", 
  2369. trenn[ ] = " \n";
  2370.             char *pos;
  2371.             int i = 0;
  2372.  
  2373.             // erstes Wort abtrennen:
  2374.             pos = strtok(s,trenn);
  2375.  
  2376.             while(pos) // d. h, solange noch Worte gefunden werden:
  2377.             {
  2378.                 // Wort ausgeben:
  2379.                 printf("Wort %2i: %s\n", ++i, pos);
  2380.  
  2381.                 // nächstes Wort ermitteln:
  2382.                 pos = strtok(0,trenn);
  2383.             }
  2384.         }
  2385.  
  2386.  
  2387. Das Programm liefert folgende Ausgabe:
  2388.  
  2389.     Wort 1: Alles
  2390.     Wort 2: Seiende
  2391.     Wort 3: entsteht
  2392.     Wort 4: ohne
  2393.     Wort 5: Grund,
  2394.     Wort 6: setzt
  2395.     Wort 7: sich
  2396.     Wort 8: aus
  2397.     Wort 9: Schwäche
  2398.     Wort 10: fort
  2399.     Wort 11: und
  2400.     Wort 12: stirbt
  2401.     Wort 13: durch
  2402.     Wort 14: Zufall.
  2403.  
  2404. memcpy
  2405.  
  2406. void *memcpy(void *v1, const void *v2, size_t n)
  2407.  
  2408.     Von Adresse "v2" werden "n" Bytes an Adresse "v1" 
  2409. kopiert. Dabei dürfen sich die beiden Speicherbereiche 
  2410. nicht überlappen. Ergebnis der Funktion ist "v1".
  2411.  
  2412. memmove
  2413.  
  2414. void *memmove(void *v1, const void *v2, size_t n)
  2415.  
  2416.     entspricht "memcpy", aber hier dürfen sich der Quell- und 
  2417. der Zielbereich auch überlappen.
  2418.  
  2419.  
  2420. memcmp
  2421.  
  2422. int memcmp(const void *v1, const void *v2, size_t n)
  2423.  
  2424.     An den Adressen "v1" und "v2" werden die jeweils ersten 
  2425. "n" Zeichen miteinander verglichen. Diese Funktion ist 
  2426. identisch mit "strncpy", aber sie vergleicht beliebige 
  2427. Daten (allerdings immer byteweise) und bricht nicht beim 
  2428. ersten Nullbyte ab.
  2429.  
  2430. memchr
  2431.  
  2432. void *memchr(const void *v, int c, size_t n)
  2433.  
  2434.     sucht analog zu "strchr" das Zeichen "c" in den ersten 
  2435. "n" Zeichen des Speichervektor "v" und liefert einen 
  2436. Zeiger auf dieses Zeichen.
  2437.  
  2438. memset
  2439.  
  2440. void *memset(void *v, int c, size_t n)
  2441.  
  2442.     schreibt das Zeichen "c" in die ersten "n" Bytes ab 
  2443. Adresse "v".
  2444.  
  2445. 1.13 Datum und Uhrzeit: <time.h>
  2446.  
  2447. clock_t
  2448.  
  2449. typedef unsigned clock_t
  2450.  
  2451.     Der ganzzahlige Datentyp "clock_t" repräsentiert eine 
  2452. Zeitangabe und wird im Zusammenhang mit der Funktion 
  2453. "clock" benutzt.
  2454.  
  2455. time_t
  2456.  
  2457. typedef unsigned time_t
  2458.  
  2459.     Auch "time_t" ist ein Datentyp und stellt so etwas wie 
  2460. eine komprimierte Form der "DateStamp"-Struktur des 
  2461. Betriebssystems dar.
  2462.  
  2463. tm
  2464.  
  2465. struct tm
  2466. { int tm_sec,  tm_min,  tm_hour, tm_mday, tm_mon, tm_year,
  2467.          tm_wday, tm_yday, tm_idst; }
  2468.  
  2469.     Die Struktur "tm" enthält alles, was zu einer Zeit- und 
  2470. Datumsangabe gehört. Die einzelnen Felder bedeuten dabei:
  2471.     tm_sec    Sekunden (0 bis 61, denn man hat hier 
  2472. lustigerweise sogar daran gedacht, daß es bis zu 2 
  2473. Schaltsekunden geben kann)
  2474.     tm_min    Minuten (0 bis 59)
  2475.     tm_hour    Volle Stunden seit Mitternacht (0 bis 23)
  2476.     tm_mday    Monatstag (1 bis 31)
  2477.     tm_mon    Monate seit Januar (d. h. von 0 bis 11!)
  2478.     tm_year     Jahre seit 1900, z. B1992
  2479.     tm_wday    Wochentag: von 0 (Sonntag) bis 6 (Samstag)
  2480.     tm_yday    Tage seit dem 1. Januar (0 bis 365)
  2481.     tm_idst    positiv, wenn Sommerzeit gilt, Null bei 
  2482. Sommerzeit und negativ, wenn das unbekannt ist (in 
  2483. MaxonC++ immer)
  2484.  
  2485. time
  2486.  
  2487. time_t time (time_t *tp)
  2488.  
  2489.     Die Funktion "time" liefert die aktuelle Systemzeit in 
  2490. Form einer "time_t"-Zahl. Wenn ihr Argument nicht Null 
  2491. ist, wird das Ergebnis zusätzlich noch in "*tp" abgelegt.
  2492.     Normalerweise benutzt mandas Ergebnis von "time" mit den 
  2493. Funktionen "difftime", "gmtime" oder "localtime".
  2494.  
  2495. gmtime
  2496.  
  2497. struct tm *gmtime (const time_t *tp)
  2498.  
  2499.     Der Inhalt von "*tp", also eine Zeitangabe in diesem 
  2500. geheimnisvollen "time_t"-Format, wird in einem ebenso 
  2501. geheimen, internen Puffer in das anwenderfreundliche 
  2502. "tm"-Format umgewandelt. Ein Zeiger auf diesen Puffer wird 
  2503. zurückgegeben, so daß man die Kalender- und Zeitdaten von 
  2504. dort auslesen kann. Es gibt aber nur einen internen 
  2505. Puffer, so daß die Daten beim nächsten Aufruf von "gmtime" 
  2506. oder ihrer Schwesterfunktion "localtime" wieder 
  2507. überschrieben werden.
  2508.  
  2509. localtime
  2510.  
  2511. struct tm *localtime(const time_t *tp)
  2512.  
  2513.     Diese Funktion unterscheidet sich von "gmtime" nur darin, 
  2514. daß die Systemzeit in "*tp" hier in Ortszeit umgewandelt 
  2515. wird (daher das "local"), während "gmtime" ein Ergebnis in 
  2516. "Coordinated Universal Time" (UTC) liefern sollte - das 
  2517. "gm" leitet sich  übrigens von der alten Bezeichnung 
  2518. "Greenwich Mean Time" ab. Unter MaxonC++ sind die beiden 
  2519. Funktionen aber absolut identisch.
  2520.  
  2521. mktime
  2522.  
  2523. time_t mktime (struct tm *tp)
  2524.  
  2525.     "mktime" ist das Gegenstück zu "localtime" und wandelt 
  2526. den Inhalt der "tm"-Struktur "*tp" in das komprimierte 
  2527. "time_t"-Format um. Im Prinzip wird dabei verlangt, daß 
  2528. alle, aber auch wirklich alle Einträge der Struktur 
  2529. korrekt initialisiert sind. MaxonC++ ist aber schon 
  2530. zufrieden, wenn die ersten sechs Member (Sekunden, 
  2531. Minuten, Stunden, Tag, Monat, Jahr) mit gültigen Werten 
  2532. initialisiert sind.
  2533.  
  2534. clock
  2535.  
  2536. clock_t clock (void)
  2537.  
  2538.     Diese Funktion liefert die bisherige Laufzeit des 
  2539. Programms. MaxonC++ implementiert diese Funktion etwas 
  2540. nachlässig, denn "clock" liefert nur die Zeit, die seit 
  2541. dem Programmstart vergangen ist, und nicht die CPU-Zeit, 
  2542. wie es eigentlich verlangt wird. Jedenfalls können Sie das 
  2543. Ergebnis von "clock" in Sekunden umrechnen, indem Sie 
  2544. durch "CLOCKS_PER_SEC" dividieren.
  2545.  
  2546. CLOCKS_PER_SEC
  2547.  
  2548. #define CLOCKS_PER_SEC 50
  2549.  
  2550.     Diese Konstante gibt den Umrechnungsfaktor zwischen 
  2551. "clock_t" und einer Zeitangabe in Sekunden an. 
  2552. "clock()/CLOCKS_PER_SEC" liefert die bisherige Laufzeit 
  2553. des Programms in Sekunden.
  2554. difftime
  2555.  
  2556. double difftime(time_t t1, time_t t2)
  2557.  
  2558.     "difftime" subtrahiert die Zeiten "t1-t2" und liefert das 
  2559. Ergebnis als Fließkommazahl in Sekunden.
  2560.  
  2561. strftime
  2562.  
  2563. int strftime(char *s, unsigned len, const char *format, 
  2564. const struct tm *t)
  2565.  
  2566.     Diese hochkomfortable Funktion wandelt die Zeit in der 
  2567. Struktur "*t"ähnlich wie die Funktion "sprintf" in eine 
  2568. Stringdarstellung um und legt diese mit einem 
  2569. abschließenden Nullzeichen im Zeichenvektor "s" ab. Dabei 
  2570. werden maximal "len" Zeichen in "s" geschrieben.
  2571.     "format" ist ein Formatstring, der wie bei "sprintf" nach 
  2572. "s" kopiert wird. Dabei werden Anweisungsfolgen, die 
  2573. jeweils mit einem "%" beginnen, durch ansprechend 
  2574. formatierte aus "*t" ersetzt. Der Rückgabewert ist die 
  2575. Anzahl der Zeichen, die in "s" geschrieben wurden, wobei 
  2576. das abschließende Nullbyte nicht mitgezählt wird. Wenn 
  2577. aber "len" Zeichen nicht reichen, ist das Ergebnis Null.
  2578. Die folgende Tabelle gibt die zahlreichen möglichen 
  2579. Umwandlungsoperatoren an:
  2580.     "    Gekürzter Wochentag, z. B. "Mon" für Montag
  2581.     %A    Vollständiger Wochentag, z. B. "Monday"
  2582.     %b    Monats-Kurzname, z. B. "Apr" füt April
  2583.     %B    Voller Name des Monats, z. B. "April"
  2584.     %c    Kurzdarstellung von Datum und Uhrzeit, z. B. "Apr 06 
  2585. 23:55:42 1992"
  2586.     %d    Monatstag ("01" bis "31")
  2587.     %H    Amerikanische Stundendarstellung ("01" bis "12")
  2588.     %I    Stunde auf Europäisch ("00" bis "23")
  2589.     %j    Tag im Jahr ("001" - "366")
  2590.     %m    Monat ("01" - "12")
  2591.     %M    Minute ("00" - "59")
  2592.     %p    "AM" oder "PM"
  2593.     %S    Sekunde ("00" - "61")
  2594.     %U    Woche im Jahr ("00"-"53"), mit Sonntag als ersten 
  2595. Wochentag
  2596.     %w     Wochentag (von "0" für Sonntag bis "6" für Samstag)
  2597.     %W    Woche im Jahr ("00"-"53"), mit Montag als ersten 
  2598. Wochentag
  2599.     %x    Datum, z. B. "Apr 06 1992"
  2600.     %X    Uhrzeit, z. B. "23:55:42"
  2601.     %y    Jahr im Jahrhundert, z. B. "92"
  2602.     %Y    Vollständige Jahreszahl, z. B. "1992"
  2603.     %Z    Name der Zeitzone (hier nicht implementiert)
  2604.     %%    Prozentzeichen
  2605.  
  2606.     Beispiel:
  2607.         #include <stream.h>
  2608.         #include <time.h>
  2609.         
  2610.         void main()
  2611.         {
  2612.             char s[80];
  2613.             time_t t = time(0);
  2614.  
  2615.             strftime(s, 80, "Es ist jetzt %X am %d. %m. %Y.\n",
  2616.             localtime(&t));
  2617.             cout Ç s;
  2618.         }
  2619.  
  2620.     gibt so etwas aus wie
  2621.     Es ist jetzt 10:47:11 am 07. 04. 1992.
  2622.  
  2623. asctime
  2624.  
  2625. char *asctime (const struct tm *t)
  2626.  
  2627.     ist eine Sparversion von "strftime" und wandelt die Zeit 
  2628. aus "*t" in eine Zeichenkette der Form "Tue Apr 07 
  2629. 01:03:42 1992" um. Diese Zeichenkette wird in einem 
  2630. internen Puffer abgelegt und ein Zeiger darauf 
  2631. zurückgegeben.
  2632.  
  2633. ctime
  2634.  
  2635. char *ctime(const time_t *t)
  2636.  
  2637.     ist identisch mit "asctime(localtime(t))", wandelt also 
  2638. einen "time_t"-Wert in eine Stringdarstellung um.
  2639.  
  2640.  
  2641. 2. Bibliotheken für C++
  2642. 2.1 Ein- und Ausgaben in C++: <stream.h> und <iostream.h>
  2643. 2.1.1 Ausgabe
  2644. 2.1.1.1 "ostream" und der Operator "Ç"
  2645. Bekanntlich ist in C++ alles viel schöner, besser und 
  2646. leichter als in ANSI C, und so ist es auch bei der Ein- 
  2647. und Ausgabe von Daten. Die dazu nötigen Definitionen 
  2648. stehen in der Includedatei "<stream.h>", während 
  2649. "<iostream.h>" nur so etwas wie ein Aliasname für erstere 
  2650. Datei ist und lediglich ein "#include <stream.h>" enthält. 
  2651. Genaugenommen ist "<stream.h>" die inzwischen veraltete 
  2652. Bezeichnung (aus dem 1.0-Standard) und "<iostream.h>" laut 
  2653. 2.0-Standard korrekter, aber letzten Endes ist das ja 
  2654. egal, denn die beiden Bezeichnungen sind absolut 
  2655. äquivalent. In diesem Handbuch wird konsequent 
  2656. "<stream.h>" benutzt.
  2657. In diesen Dateien wird unter anderem die Klasse "ostream" 
  2658. definiert, die für Ausgaben aller Art zuständig ist. Es 
  2659. gibt drei Standard-Objekte dieses Typs:
  2660.     cout    für gewöhnliche Ausgaben
  2661.     cerr    für Fehlermeldungen, die sofort ausgegeben werden
  2662.     clog    für gepufferte Fehlermeldungen
  2663.  
  2664. MaxonC++ nimmt sich die Freiheit, daß "cerr" und "clog" 
  2665. unterschiedliche Namen für ein und dasselbe Objekt sind.
  2666. Auf dieser Klasse "ostream" ist vor allem der Operator "Ç" 
  2667. mehrfach überladen. Der linke Operand ist dabei jeweils 
  2668. ein "ostream"-Objekt, über das die Ausgabe erfolgen soll, 
  2669. z. B. "cout", und der rechte Operand ist ein Ausdruck 
  2670. eines Standard-Typs. Im einzelnen sind folgende 
  2671. Operatorfunktionen als Member definiert:
  2672. ostream &operator Ç (int)
  2673. ostream &operator Ç (unsigned)
  2674. ostream &operator Ç (long)
  2675. ostream &operator Ç (unsigned long)
  2676. ostream &operator Ç (long long)
  2677. ostream &operator Ç (unsigned long long)
  2678. ostream &operator Ç (unsigned char)
  2679. ostream &operator Ç (signed char)
  2680. ostream &operator Ç (char)
  2681. ostream &operator Ç (const char *)
  2682. ostream &operator Ç (float)
  2683. ostream &operator Ç (double)
  2684. ostream &operator Ç (long double)
  2685. ostream &operator Ç (const void*)
  2686. ostream &operator Ç (form &)
  2687. ostream &operator Ç (ios&(*f)(ios&))
  2688.  
  2689. Wie unschwer zu erkennen ist, gibt es für jeden 
  2690. numerischen Datentyp eine Ausgabefunktion (die Typen 
  2691. "short" und "unsigned short" werden gemäß den 
  2692. C++-Typregeln nach "int" umgewandelt und mit der 
  2693. entsprechenden Funktion ausgegeben). "signed char"- und 
  2694. "unsigned char"-Werte werden hier als Zahlen 
  2695. interpretiert, während bei "char" ein Zeichen ausgegeben 
  2696. wird. Bei einem Zeichenkettenargument ("const char*") wird 
  2697. natürlich der entsprechende String ausgegeben, während bei 
  2698. einem beliebigen anderen Pointer ("const void*") die 
  2699. Speicheradresse als hexadezimale Zahl mit vorangestelltem 
  2700. "0x" ausgegeben wird. Das kann natürlich zu Überraschungen 
  2701. führen, wenn man die Adresse einer "char"-Variablen 
  2702. ausgeben will:
  2703. #include <stream.h>
  2704.  
  2705. void main()
  2706. {
  2707. int i;
  2708. char c;
  2709.  
  2710. cout Ç &i;         // gibt Adresse von "i" hexadezimal aus
  2711. cout Ç &c;         // verunglückte String-Ausgabe
  2712. }
  2713.  
  2714. Hier versucht der Compiler, der nun einmal hinreichend 
  2715. dämlich ist, "c" als String zu interpretieren, und das 
  2716. Programm gibt alle Zeichen von "c" bis zum ersten im 
  2717. Speicher folgenden Nullbyte aus.
  2718. Außerdem stoßen die beiden letzten Funktionsdeklarationen 
  2719. in der obigen Liste bei Ihnen vielleicht auf 
  2720. Unverständnis. Die Funktion
  2721. ostream &ostream::operator Ç (form &)
  2722.  
  2723. stellt über die Klasse "form" eine formatierte Ausgabe im 
  2724. C-Stil zur Verfügung (siehe auch 2.1.1.3), und
  2725. ostream &ostream::operator Ç (ios&(*f)(ios&))
  2726.  
  2727. wendet eine Funktion auf eine Basisklasse von "ostream" an 
  2728. (2.1.1.3).
  2729. Das Ergebnis all dieser Funktionen ist stets eine Referenz 
  2730. auf das "ostream"-Objekt, so daß man mehrere Ausgaben 
  2731. aneinander hängen kann, z. B.:
  2732. int i=0x2a;
  2733. cout Ç "Der Wert von i ist: " Ç i Ç «\n«;
  2734.  
  2735. Auch wenn die Werte natürlich in der Reihenfolge 
  2736. ausgegeben werden, in der man sie hinschreibt, kann ihre 
  2737. Auswertungsreihenfolge durchaus eine andere sein:
  2738. int i = 40;
  2739.  
  2740. cout Ç ++i Ç ++i;
  2741.  
  2742. Die Ausgabe kann hier entweder "4142" oder "4241" sein 
  2743. (die Ausgabe von Zahlen erfolgt ohne trennende oder 
  2744. führende Leerzeichen), denn voll ausgeschrieben entspricht 
  2745. dieser Ausdruck
  2746. cout.operatorÇ(++i).operatorÇ(++i)
  2747.  
  2748. und die Auswertungsreihenfolge in Ausdrücken ist in C++ 
  2749. nur in bestimmten Ausnahmefällen vorgeschrieben.
  2750.  
  2751. 2.1.1.2 Basen und Manipulatoren
  2752. Die Klasse "ostream" hat noch eine Basisklasse namens 
  2753. "ios". Aus bestimmten Gründen wird "ostream" sogar 
  2754. virtuell davon abgeleitet, aber das interessiert momentan 
  2755. nicht so unbedingt. Jedenfalls existieren ein paar 
  2756. Funktionen, nämlich "dec", "hex", "oct", "endl" und 
  2757. "flush", die als Parameter eine Referenz auf ein solches 
  2758. "ios"-Objekt erwarten und dieselbe Referenz als Ergebnis 
  2759. liefern. Da eine abgeleitete Klasse alle Eigenschaften 
  2760. ihrer Basisklassen erbt, kann man diese Funktionen 
  2761. natürlich auch auf die Klasse "ostream" anwenden.
  2762.  
  2763. Die drei Funktionen
  2764. ios &dec (ios &s)
  2765. ios &hex (ios &s)
  2766. ios &oct (ios &s)
  2767.  
  2768. setzen die Zahlbasis in einem Strom-Objekt. Nach einem 
  2769. Funktionsaufruf wie
  2770. hex(cout)
  2771.  
  2772. werden in Zukunft über "cout" alle ganzzahligen Werte 
  2773. hexadezimal, aber ohne vorangestelltes "0x", ausgegeben. 
  2774. Die Ausgabe von Fließkomma- oder Stringwerten wird dadurch 
  2775. nicht beeinflußt.
  2776. Analog schaltet die Funktion "oct" auf oktale 
  2777. Zahldarstellung um, und "dec" stellt wieder den dezimalen 
  2778. Modus her.
  2779.  
  2780. Ein Beispiel:
  2781. #include <stream.h>
  2782.  
  2783. void main()
  2784. {
  2785.     int i = 42;
  2786.     hex(cout);
  2787.     cout Ç "hexadezimal: " Ç i Ç "\n";
  2788.     dec(cout);
  2789.     cout Ç "dezimal:     " Ç i Ç "\n";
  2790.     oct(cout);
  2791.     cout Ç "oktal:       " Ç i Ç "\n";
  2792.     cout Ç "Es gilt die jeweils zuletzt gewählte Einstellung: 
  2793. "
  2794.     Ç i Ç "\n";
  2795. }
  2796.  
  2797. Das Programm gibt aus:
  2798. hexadezimal:    2a
  2799. dezimal:    42
  2800. oktal:    52
  2801.  
  2802. Es gilt die jeweils zuletzt gewählte Einstellung: 52
  2803. Wie Sie an der letzten Ausgabe erkennen können, gelten die 
  2804. so vorgenommenen Einstellungen auch über eine Ausgabezeile 
  2805. hinaus, nämlich so lange, bis wieder ein anderer Modus 
  2806. gewählt wird.
  2807. Ein- und Ausgabedateien, und ein C++-Strom repräsentiert 
  2808. im Grunde genommen nichts anderes, werden oft mit einem 
  2809. Puffer beschleunigt (siehe auch 1.2.6.2). Die Funktion
  2810. ios &flush (ios &s)
  2811.  
  2812. löscht den Schreibpuffer eines Ausgabestroms, indem sie 
  2813. seinen Inhalt ausgibt. Wenn der Strom keinen Puffer hat, 
  2814. hat die Funktion keinerlei Wirkung. Maxon C++ weist den 
  2815. Standard-Ausgabeströmen als Default zwar keinen Puffer zu, 
  2816. aber auf einigen Systemen ist nach einer Ausgabe ein 
  2817. "flush(cout)" bzw. "flush(clog)" nötig, um die Ausgabe 
  2818. wirklich zu schreiben.
  2819. Natürlich kann man diese Funktion auch so benutzen:
  2820. flush(cout Ç "Ausgabe");
  2821.  
  2822. ...oder so:
  2823. flush(cout) Ç "Ausgabe";
  2824.  
  2825. Der erste Ausdruck gibt erst etwas aus und wendet dann 
  2826. "flush" an, die zweite Anweisung schreibt erst einen 
  2827. etwaigen Pufferinhalt und macht dann eine weitere Ausgabe, 
  2828. die aber gegebenenfalls natürlich zunächst in einem Puffer 
  2829. aufbewahrt wird.
  2830. Last not least gibt es noch die Funktion
  2831. ios &endl (ios &s)
  2832.  
  2833. Sie gibt einen Zeilentrenner in einen Strom aus und ruft 
  2834. anschließend "flush" auf:
  2835. cout Ç "Das Ergebnis ist: " Ç Resultat;
  2836. endl(cout);
  2837.  
  2838. oder
  2839. endl(cout Ç "Das Ergebnis ist: " Ç Resultat);
  2840.  
  2841. entspricht
  2842. cout Ç "Das Ergebnis ist: " Ç Resultat;
  2843. flush(cout Ç "\n");
  2844.  
  2845. Diese kleinen Funktionen sind zwar ganz praktisch, aber 
  2846. ihre Handhabung und der damit verbundene Schreibaufwand 
  2847. entsprechen, wie auch die Übersichtlichkeit, doch eher dem 
  2848. C-Niveau als einem angenehmen C++-Stil. Deshalb gibt es 
  2849. die Funktion
  2850. ostream &ostream::operator Ç (ios&(*f)(ios&))
  2851.  
  2852. Wenn man die Adresse einer Funktion mit der passenden 
  2853. Signatur in ein "ostream"-Objekt "schreibt", wird sie 
  2854. darauf ausgeführt:
  2855. cerr Ç hex
  2856.  
  2857. ist damit äquivalent zu
  2858. hex(cerr)
  2859.  
  2860. Das eröffnet dem Programmierer reizvolle Möglichkeiten:
  2861. cout Ç hex Ç 26731 Ç endl;
  2862.  
  2863. schaltet die Standard-Ausgabe auf hexadezimale Ausgabe um, 
  2864. schreibt dann in eben diesem Modus eine Zahl und führt 
  2865. "endl" aus. Auf diese Weise wird die Handhabung solcher 
  2866. Funktionen doch erheblich angenehmer und intuitiver.
  2867.  
  2868. 2.1.1.3 Formatierte Ausgabe
  2869. Die Klasse "form" stellt eine formatierte Ausgabe im Stil 
  2870. von "printf" zur Verfügung. Sie hat einen Konstruktor, 
  2871. dessen Parameter demgemäß eine nicht ganz unzufällige 
  2872. Ähnlichkeit mit denen von "printf" haben:
  2873. form(const char *fmt, ...)
  2874.  
  2875. In der Formatzeichenkette können sämtliche 
  2876. Umwandlungsoperationen und Optionen von "printf" (siehe 
  2877. 1.2.4) benutzt werden, und an Stelle der Ellipse "..." 
  2878. sind die entsprechenden zusätzlichen Argumente zu setzen. 
  2879. Man kann sich ein solches "form"-Objekt erzeugen und mit 
  2880. dem gewöhnlichen Operator "Ç" in einen "ostream" ausgeben:
  2881.  
  2882. #include <stream.h>
  2883.  
  2884. void main()
  2885. {
  2886. int i=42;
  2887. char s[ ] = "die große Frage";
  2888.  
  2889. form f("Die Antwort auf %s ist %d.\n", s, i);
  2890.  
  2891. cout Ç f;
  2892. }
  2893.  
  2894. In dem Objekt "f" wird hier der String
  2895. "Die Antwort auf die große Frage ist 42.\n"
  2896.  
  2897. abgespeichert und kann beliebig oft ausgegeben werden. 
  2898. Gebräuchlicher ist aber wohl die Möglichkeit, ein 
  2899. namenloses, temporäres Objekt auszugeben:
  2900. cout Ç form("Hex: %x", 42) Ç endl;
  2901.  
  2902. Auf diese Weise stehen auch bei den C++-Streams sämtliche 
  2903. Formatierungsmöglichkeiten von "printf" zur Verfügung. Der 
  2904. Nachteil ist natürlich, daß auch "form" eine Funktion ohne 
  2905. Netz und doppelten Boden ist und der Programmierer deshalb 
  2906. selbst darauf zu achten hat, daß die Argumente stimmen.
  2907.  
  2908. 2.1.1.4 Ausgabe binärer Daten
  2909. Die Standardausgabe ist in der Regel ein Fenster, oder sie 
  2910. wird auch manchmal in eine (Text-)Datei umgelenkt. Deshalb 
  2911. wird man normalerweise über "cout", "cerr" und "clog" nur 
  2912. formatierte Textdaten ausgeben. Man kann einen "ostream" 
  2913. aber auch an eine Datei anbinden, und dann wird man 
  2914. durchaus manchmal auch binäre Daten schreiben wollen. 
  2915. Deshalb gibt es die beiden Memberfunktionen
  2916. ostream &ostream::put (char c)
  2917. ostream &ostream::write (const char *p, int n)
  2918. Erstere Funktion schreibt ein Zeichen in einen 
  2919. Ausgabestrom, letztere die ersten "n" Bytes ab Adresse 
  2920. "p". Daß "p" hier ein Zeiger auf "char" ist, sollte Sie 
  2921. nicht weiter beunruhigen, denn natürlich können Sie 
  2922. beliebige andere Zeiger nach "char*" casten.
  2923. Einige Beispiele:
  2924. cout.write("Hello, World!",5)
  2925.  
  2926. schreibt die Zeichenfolge "Hello" nach "cout", und
  2927. double d = 3.14159;
  2928. cout.write((char*) &d, sizeof(double));
  2929.  
  2930. schreibt die "double"-Zahl "d" in denselben Strom, aber 
  2931. nicht als lesbare, formatierte Zahldarstellung, sondern in 
  2932. Form von (hier)acht Bytes.
  2933. Das erste Beispiel ist durchaus sinnvoll (manchmal möchte 
  2934. man wirklich nur einen Teil eines Strings ausgeben, oder 
  2935. man hat eine Zeichenkette vorliegen, bei der das Nullbyte 
  2936. am Ende fehlt), während das letztere wirklich nur bei 
  2937. Dateioperationen einen sittlichen Nährwert hat.
  2938.  
  2939. 2.1.2 Eingabe
  2940. 2.1.2.1 Texteingaben mit "È"
  2941. Was Krupp in Essen, wir im Trinken und "ostream" bei der 
  2942. Ausgabe, ist die Klasse "istream" für die Eingabe von 
  2943. Daten. Es gibt ein Standard-Objekt dieser Klasse namens 
  2944. "cin", das in "<stream.h>" deklariert wird und die 
  2945. Standard-Eingabe eines Programms darstellt, also 
  2946. normalerweise die Eingaben des Benutzers.
  2947. Die folgenden Operatoren sind als Member von "istream" 
  2948. deklariert:
  2949. istream & operator È (char s[ ])
  2950. istream & operator È (char &c)
  2951. istream & operator È (signed char &sc)
  2952. istream & operator È (unsigned char &uc)
  2953. istream & operator È (short &s)
  2954. istream & operator È (unsigned short &us)
  2955. istream & operator È (int &i)
  2956. istream & operator È (unsigned &u)
  2957. istream & operator È (long &l)
  2958. istream & operator È (unsigned long &ul)
  2959. istream & operator È (long long &vl)
  2960. istream & operator È (unsigned long long &uvl)
  2961. istream & operator È (float &f)
  2962. istream & operator È (double &d)
  2963. istream & operator È (long double &ld)
  2964.  
  2965. Linker Operand ist jeweils ein Objekt der Klasse 
  2966. "istream", also insbesondere die Variable "cin", und eine 
  2967. Referenz auf genau dieses Objekt ist auch der Rückgabewert 
  2968. dieser Operatorfunktionen. Als rechter Operand kann, wie 
  2969. Sie der imposanten Auflistung von Funktionen unschwer 
  2970. entnehmen können, ein L-Wert eines beliebigen numerischen 
  2971. Standardtyps (einschließlich "char") oder eine 
  2972. Stringvariable dienen. Die Operatorfunktion liest dann die 
  2973. benötigte Anzahl von Zeichen aus dem Eingabestrom, wandelt 
  2974. sie in den gewünschten Datentypen um (z. B. eine 
  2975. Ziffernfolge in eine ganze Zahl) und weist das Resultat 
  2976. dem rechten Operanden zu.
  2977.  
  2978. Ein Beispiel:
  2979. int i;
  2980. char c;
  2981. char s[50];
  2982.  
  2983. cin È c È i È s;
  2984.  
  2985. Bei der Eingabe
  2986. 0815-4711 42
  2987.  
  2988. wird "c" das Zeichen "0" zugewiesen, "i" bekommt den Wert 
  2989. "815" und in "s" wird die Zeichenkette "-4711" abgelegt, 
  2990. während die Zeichen "42" vorerst unbeachtet bleiben und 
  2991. vielleicht bei der nächsten Eingabe Beachtung finden. 
  2992. Liest man auf diese Weise ein "char", werden zuerst 
  2993. Leerzeichen, Zeilentrenner und sonstige Leerraum-Zeichen 
  2994. überlesen. Beim Lesen von Strings werden ebenfalls 
  2995. Trennzeichen überlesen, und es wird bis ausschließlich zum 
  2996. nächsten nachfolgenden Trennzeichen gelesen. Somit wirkt 
  2997. also - zumindest beim Operator "È" - auch ein Leerzeichen 
  2998. als Trennung zwischen zwei Strings.
  2999. Auch die Klasse "istream" kann nicht hellsehen, und 
  3000. deshalb weiß die Eingabe-Operatorfunktion "È", wenn sie 
  3001. auf eine Stringvariable angewandt wird, nicht, wie lang 
  3002. dieser String ist. Das kann zu üblen Abstürzen führen, 
  3003. wenn der Anwender bei
  3004. char input[20];
  3005.  
  3006. cin È input;
  3007.  
  3008. mehr als 20 Zeichen eingibt. Um dies halbwegs sicher zu 
  3009. gestalten, liest die Funktion in Maxon C++ maximal 
  3010. "STREAM_MAXSTRING" Zeichen in Stringvariablen, und zwar 
  3011. einschließlich des Nullbytes am Ende. Diese Konstante wird 
  3012. in "<stream.h>" als 80 definiert - ein kanonischer Wert 
  3013. für eine vernünftige Zeilenlänge. Leider handelt es sich 
  3014. dabei um eine Spezialität von MaxonC++ und nicht um einen 
  3015. wirklichen Standard.
  3016. Ganzzahlige Werte können wahlweise dezimal, oktal (mit 
  3017. führender Null) oder hexadezimal (mit "0x" oder "0X" am 
  3018. Anfang) eingegeben werden. Fließkommazahlen werden 
  3019. natürlich nur dezimal akzeptiert und können einen 
  3020. Exponententeil (mit "e" oder "E" eingeleitet) haben.
  3021.  
  3022. 2.1.2.2 Eingabefunktionen auf "istream"
  3023. Die Memberfunktion "read" liest aus einem "istream" eine 
  3024. beliebige Anzahl von Bytes und legt sie in einem 
  3025. Zielvektor ab. Damit ist sie das Gegenstück zur 
  3026. ANSI-Funktion "fread". Sie ist definiert als
  3027. istream & istream::read(char buf, int n)
  3028.  
  3029. Auch hier sollte es Sie nicht weiter beunruhigen, daß der 
  3030. Zielvektor "buf" formal ein "char"-Array ist, denn man 
  3031. kann natürlich jeden Pointer in ein "char*" umwandeln. "n" 
  3032. ist die Anzahl der Bytes, die gelesen werden sollen, und 
  3033. muß natürlich positiv sein. Das Ergebnis der Funktion ist 
  3034. wie immer eine Referenz auf das "istream"-Objekt.
  3035. Drei weitere Funktionen, die allesamt "get" heißen, lesen 
  3036. jeweils ein Zeichen aus dem Eingabestrom und sind 
  3037. folgendermaßen definiert:
  3038. istream &    istream::get (char &c)
  3039. istream &    istream::get (unsigned char &c)
  3040. int    istream::get ()
  3041.  
  3042. Die beiden ersten Funktionen lesen das Zeichen in eine 
  3043. "char"-Variable und liefern die übliche Referenz als 
  3044. Ergebnis. Sie sind gleichermaßen auf "char" und "unsigned 
  3045. char" definiert. Die dritte Funktion expandiert das 
  3046. Zeichen nach "int" und liefert es als Ergebnis.
  3047. Der Unterschied zwischen
  3048. cin È c
  3049.  
  3050. und
  3051. cin.get(c)
  3052.  
  3053. besteht darin, daß "get" keinen Leerraum überspringt, also 
  3054. zeichenweise die vollständige Eingabe einschließlich aller 
  3055. Leerzeichen und Zeilentrenner liest.
  3056. Oft merkt man, daß man genug gelesen hat, erst, nachdem 
  3057. man schon zu viel gelesen hat. In diesem Fall hilft die 
  3058. Funktion "putback", die ein bereits gelesenes Zeichen in 
  3059. den Eingabestrom zurückstellt:
  3060. istream & istream::putback(char c)
  3061.  
  3062. Auf diese Weise kann aber immer höchstens ein Zeichen 
  3063. gepuffert werden.
  3064. Besonders beim Lesen aus Dateien muß man irgendwie wissen, 
  3065. wann man am Ende der Datei angelangt ist. Deshalb bietet 
  3066. "istream" auch eine Memberfunktion, die eben dieses testet:
  3067. int istream::eof()
  3068.  
  3069. Das Ergebnis dieser Funktion ist von Null verschieden, 
  3070. wenn das Dateiende überschritten wurde. Damit entspricht 
  3071. die Funktion "feof" aus "<stdio.h>".
  3072. Nun fehlt noch eine Funktion, die eine Textzeile liest. 
  3073. Hier ist sie:
  3074. istream &getline(char *buf, int len, char Delim = «\n«)
  3075.  
  3076. Es werden maximal "len"-1 Zeichen in den Vektor "buf" 
  3077. gelesen. Die Funktion bricht ab, sobald ein Trennzeichen 
  3078. "Delim" gelesen wird - als Default ist dies der 
  3079. Zeilentrenner. Dieses Trennzeichen wird zwar aus dem 
  3080. Eingabestrom gelesen und nicht wieder zurückgestellt, aber 
  3081. nicht in "buf" abgelegt.
  3082.  
  3083. 2.1.3 Weitere Funktionen
  3084. 2.1.3.1 Die Schnittstelle zum ANSI C-Dateisystem
  3085. Oben wurde bereits angedeutet, daß die "stream"-Funktionen 
  3086. von MaxonC++ im wesentlichen verkleidete ANSI-C-Funktionen 
  3087. sind. Diese Schnittstelle kann der Programmierer durch die 
  3088. Funktion "getstream" der Klasse "ios" nutzen:
  3089. FILE * ios::getstream()
  3090.  
  3091. Diese Funktion liefert als Ergebnis einen Zeiger auf den 
  3092. ANSI C- Filedeskriptor. Damit lassen sich sämtliche 
  3093. Funktionen aus "<stdio.h>" auch auf C++-Streams benutzen.
  3094. Außer den hinlänglich bekannten Objekten "cout", "cin" und 
  3095. so weiter kann man auch selbst Objekte der Klassen 
  3096. "istream" und "ostream" erzeugen. Zu diesem Zweck haben 
  3097. die beiden genannten Klassen jeweils einen Konstruktor, 
  3098. der als Argument einen Dateizeiger erwartet.
  3099. Ein Beispiel:
  3100. #include <stream.h>
  3101. #include <stdio.h>
  3102.  
  3103. void main()
  3104. {
  3105.     FILE *f = fopen("test", "r");        // C-File öffnen
  3106.     if (f)
  3107.     {
  3108.         istream is(f);                        // eigenes 
  3109. "istream"-Objekt
  3110.         char s[80];
  3111.  
  3112.         is È s;                              // liest einen String
  3113.  
  3114.         fclose(f);                            // Datei wieder schließen
  3115.     }
  3116. }
  3117.  
  3118. "istream" und "ostream" haben keine Destruktoren, die die 
  3119. Dateien nachher automatisch schließen. Schon allein 
  3120. deshalb ist es nicht unbedingt sinnvoll, auf diese Weise 
  3121. mit Dateien zu arbeiten - mit den Klassen und Funktionen 
  3122. aus "<fstream.h>" geht das viel einfacher.
  3123.  
  3124. 2.1.3.2 Fehlererkennung
  3125. Mit einer etwas eigenartigen Funktion bieten die 
  3126. Strom-Klassen eine äußerst intuitive Möglichkeit, Fehler 
  3127. in Dateien zu erkennen: In der Basisklasse "ios" gibt es 
  3128. eine Konvertierungsfunktion
  3129. ios::operator void*()
  3130.  
  3131. Diese Funktion liefert "0", wenn das Dateiende 
  3132. überschritten oder ein anderer Fehler bemerkt wurde, und 
  3133. andernfalls einen Zeiger auf das Objekt selbst. Das sieht 
  3134. zunächst seltsam aus, ist aber um so einfacher anzuwenden: 
  3135. Damit kann man Objekte und Ausdrücke des Typs "ios" oder 
  3136. davon abgeleiteter Klassen direkt in Abfragen einsetzen, 
  3137. z. B. so:
  3138. cin È s;
  3139. if (cin)
  3140. { usw.
  3141.  
  3142. ...oder auch so:
  3143.  char s[80];
  3144.  
  3145. while (cin È s)
  3146. cout Ç s;
  3147.  
  3148. Solche Ausdrücke sind logisch wahr, wenn kein Fehler 
  3149. aufgetreten und das Dateiende nicht erreicht ist. 
  3150. Natürlich kann man auf solche Abfragen auch die logischen 
  3151. Operatoren "!", "&&" und "||" anwenden.
  3152. Kanonisch wäre natürlich gewesen, statt dieses komischen 
  3153. "void"-Zeigers eine Konvertierungsfunktion nach "int" oder 
  3154. einem anderen numerischen Typ zu implementieren, denn ein 
  3155. Zeiger als Bedingung ist doch ein wenig 
  3156. gewöhnungsbedürftig. Das ist aber nicht möglich, weil die 
  3157. Standard-Operatoren "È" und "Ç" auf ganzzahligen Werten 
  3158. definiert sind und Ausdrücke wie "cout Ç n" damit 
  3159. mehrdeutig würden.
  3160.  
  3161. 2.2 Ströme und Dateien: <fstream.h>
  3162. 2.2.1 Klassen für Dateien
  3163. Die Standard-Ein- und Ausgabeströme sind zwar ganz nett, 
  3164. aber natürlich braucht man daneben auch "richtige" 
  3165. Dateien, und es wäre angenehm, wenn man alle Features aus 
  3166. "<stream.h>" auch mit beliebigen Dateien benutzen könnte. 
  3167. Deshalb gibt es die Includedatei "<fstream.h>", in der 
  3168. Klassen und Funktionen für Dateien definiert werden.
  3169. In <fstream.h> werden drei für Sie interessante Klassen 
  3170. definiert:
  3171.     "ifstream" für Eingaben aus Dateien,
  3172.     "ofstream" für Ausgaben in Dateien,
  3173.     "fstream" für Ein- und Ausgaben.
  3174.  
  3175. "ifstream" ist von "istream" (und damit indirekt von 
  3176. "ios") abgeleitet und erbt damit alle in 2.1.2 
  3177. vorgestellten Eigenschaften. Entsprechend wurde "ofstream" 
  3178. von "ostream" abgeleitet, während "fstream" - ein 
  3179. interessantes Beispiel für Mehrfachvererbung - 
  3180. gleichzeitig "istream" und "ostream" als Basisklassen hat.
  3181. Die drei neuen Klassen haben außer diesen ererbten 
  3182. Funktionen auch noch einen Satz von elementaren 
  3183. Dateifunktionen, etwa Öffnen und Schließen von Dateien. 
  3184. Diese gemeinsamen Eigenschaften werden in der Klasse 
  3185. "fstreambase" zusammengefaßt, die ebenfalls Basisklasse 
  3186. von "ifstream", "ofstream" und "fstream" ist.
  3187.  
  3188. 2.2.2 Dateien öffnen und schließen
  3189. Die drei oben vorgestellten Datei-Stromklassen besitzen 
  3190. jeweils einen Default-Konstruktor. Wird aber ein 
  3191. Klassenobjekt damit erzeugt, ist es zunächst an keine 
  3192. physikalische Datei "angebunden", und alle Ein- und 
  3193. Ausgabeoperationen führen unabwendbar zu einem Absturz. 
  3194. Deshalb muß zunächst die Member-Funktion "open" der 
  3195. gemeinsamen Basisklasse "fstreambase" aufgerufen werden:
  3196. FILE * fstreambase::open (const char *name, int mode)
  3197.  
  3198. Der erste Parameter steht, wie man sich denken kann, für 
  3199. den Dateinamen, während der zweite den Zugriffsmodus 
  3200. festlegt. Mögliche Werte dafür werden von einem 
  3201. Aufzählungstyp, der in der Klasse "ios" verborgen ist, 
  3202. definiert:
  3203. enum open_mode
  3204. {
  3205. in  = 1,          // Eingaben
  3206. out = 2,          // Ausgaben
  3207. app = 4           // Anhängen
  3208. }
  3209.  
  3210. Beim Modus "out" wird stets eine neue Datei erzeugt. 
  3211. Existiert bereits eine Datei gleichen Namens, so wird 
  3212. diese gelöscht.
  3213. Das folgende Programm öffnet eine Datei und schreibt eine 
  3214. Zeile hinein:
  3215. #include <fstream.h>
  3216.  
  3217. const char dateiname[ ] = "ram:Test";
  3218.  
  3219. void main()
  3220. {
  3221. ofstream os;
  3222. os.open(dateiname, ios::out);
  3223. os Ç "Dies ist die Datei " Ç dateiname Ç ".\n";
  3224. os.close();
  3225. }
  3226.  
  3227. Wie Sie sehen, haben wir oben bereits eine weitere 
  3228. Funktion aus der Klasse "fstreambase" benutzt, nämlich 
  3229. "close". Diese Funktion schließt die Datei, an die der 
  3230. Strom gebunden ist. Ein überflüssiges "close" schadet 
  3231. nicht. Nach dem Schließen ist das Stream-Objekt wieder an 
  3232. keinerlei Datei angekoppelt, und man kann, wenn man will, 
  3233. erneut eine Datei öffnen.
  3234. Kommen wir noch einmal auf die Zugriffsmodi von "open" 
  3235. zurück: Die drei vorgegebenen Werte können durch bitweises 
  3236. "Oder" miteinander kombiniert werden. Beispielsweise steht
  3237. ios::in|ios::out
  3238.  
  3239. für Lesen und Schreiben zugleich, oder beim Modus
  3240. ios::out|ios::app
  3241.  
  3242. wird zwar aus der Datei gelesen, aber der Lesezeiger steht 
  3243. zunächst am Ende der Datei und muß dann z. B. mit "seekg" 
  3244. (siehe unten) zurückgesetzt werden.
  3245.  
  3246. 2.2.3 Fehlererkennung
  3247. Selbstverstädlich sollte man immer, wenn man eine Datei 
  3248. öffnen läßt, prüfen, ob das auch wirklich geklappt hat, 
  3249. bevor man etwas mit der Datei anstellt. Dazu dient wieder 
  3250. die normale Fehlerkontrolle mit der eigenartigen 
  3251. Konvertierungsfunktion aus 2.1.3.2. Diese ist nämlich 
  3252. immer logisch "falsch", wenn ein Strom an keine Datei 
  3253. angekoppelt ist.
  3254. Das folgende Programm demonstriert dies, indem es eine 
  3255. Datei zum Lesen öffnet und sie dann in eine andere Datei 
  3256. kopiert:
  3257. #include <fstream.h>
  3258.  
  3259. void main()
  3260. {
  3261.     ifstream is;
  3262.     is.open("s:startup-sequence", ios::in);
  3263.  
  3264.     if(is)
  3265.     {
  3266.         ofstream os;
  3267.         os.open("ram:copy_of_s-seq", ios::out);
  3268.  
  3269.         if (os)
  3270.         {
  3271.             char s[80];
  3272.             while (is.getline(s,80))
  3273.                 os Ç s Ç "\n";
  3274.             os.close();
  3275.         }
  3276.         else
  3277.             cout Ç "Kann Ausgabedatei nicht öffnen";
  3278.  
  3279.         is.close();
  3280.     }
  3281.     else
  3282.         cout Ç "Kann Eingabedatei nicht öffnen";
  3283. }
  3284. 2.2.4 Konstruktoren und Destruktoren
  3285. Natürlich geht in C++ alles viel einfacher als in C, und 
  3286. so ist es auch bei diesen Dateioperationen. Ich verschwieg 
  3287. Ihnen bisher, daß "ifstream", "ofstream" und "fstream" 
  3288. jeweils nicht nur einen Default-Konstruktor haben, sondern 
  3289. auch einen solchen, dessen Parameter mit denen der 
  3290. "open"-Funktion identisch sind. Dadurch kann man die 
  3291. Definition eines Dateiobjekts mit dem Öffnen der Datei 
  3292. aufs einfachste kombinieren, z. B. so:
  3293. ofstream outf("C++:Ausgabe", ios::out);
  3294.  
  3295. Außerdem ist für diesen Konstruktor bei "ofstream" als 
  3296. Default-Argument für den zweiten Parameter "ios::out" 
  3297. definiert, so daß die Deklaration sich verkürzt zu:
  3298. ofstream outf("C++:Ausgabe");
  3299.  
  3300. Einen entsprechenden Konstruktor gibt es auch für die 
  3301. Klasse "ifstream", nur natürlich mit "ios::in" als 
  3302. Default-Argument. Auch für "fstream" existiert ein solcher 
  3303. Konstruktor, hier aber ohne einen abkürzenden 
  3304. Default-Modus.
  3305. Auch nachdem man ein Objekt auf diese erzeugt hat, muß man 
  3306. natürlich zuerst prüfen, ob die Datei auch wirklich 
  3307. geöffnet werden konnte, bevor man irgendwelche Ein- oder 
  3308. Ausgaben tätigt.
  3309. Außerdem haben die drei File-Stream-Klassen jeweils einen 
  3310. Destruktor, der die an das Objekt angebundene Datei 
  3311. schließt, sofern dies nicht schon geschehen ist. Er macht 
  3312. das natürlich unabhängig davon, mit welchem Konstruktor 
  3313. das Objekt erzeugt wurde.
  3314. Als Beispiel folgt noch einmal das in 2.2.3 vorgestellte 
  3315. Programm, diesmal aber unter Ausnutzung der Kon- und 
  3316. Destruktoren und mit vereinfachter Fehlerbehandlung:
  3317. #include <fstream.h>
  3318.  
  3319. void main()
  3320. {    ifstream is("s:startup-sequence", ios::in);
  3321.     ofstream os("ram:another_copy_of_s-seq", ios::out);
  3322.  
  3323.     if(is && os)
  3324.     {    char s[80];
  3325.         while (is.getline(s,80))
  3326.             os Ç s Ç "\n";
  3327.         os.close();
  3328.     }
  3329.     else
  3330.         cout Ç "Kann nicht beide Dateien öffnen.";
  3331. }
  3332.  
  3333.  
  3334. 2.2.5 Puffer
  3335. Auch bei den Strömen gibt es wieder das alte Elend, daß 
  3336. Dateioperationen nervtötend langsam sind, wenn byteweise 
  3337. oder in ähnlich kleinen Happen gelesen oder geschrieben 
  3338. werden muß. Deshalb gibt es in der Klasse "fstreambase" 
  3339. (also der gemeinsamen Basisklasse der drei Stromklassen) 
  3340. zwei Funktionen, deren Funktion sich dem geneigten Leser 
  3341. möglicherweise intuitiv erschließt:
  3342. int fstreambase::buffer (unsigned s)
  3343. void fstreambase::flush ()
  3344.  
  3345. "buffer" verleiht einer Datei einen Puffer der Größe "s" 
  3346. und entspricht damit einem "<stdio-.h>"-Aufruf wie
  3347. setvbuf(getstream(), 0, _IOFBF, s)
  3348.  
  3349. Man kann einen Puffer für eine Datei immer nur einmal 
  3350. setzen und danach seine Größe nicht mehr verändern. Der 
  3351. benötigte Speicherplatz wird automatisch angefordert und 
  3352. beim Schließen der Datei ebenso automatisch wieder 
  3353. freigegeben. Das Ergebnis von "buffer" ist übrigens Null, 
  3354. wenn dabei kein Fehler auftrat.
  3355. "flush" schreibt den Inhalt eines Schreibpuffers in die 
  3356. Datei.
  3357.  
  3358. 2.2.6 Positionieren in Strömen
  3359. Von den grundlegenden Dateioperationen fehlen jetzt nur 
  3360. noch Operationen zum Ermitteln und Setzen der 
  3361. Dateiposition. Zunächst wäre da die Funktion
  3362. int fstreambase::seekg (long offset, int mode = ios::beg)
  3363.  
  3364. Hier gibt es drei verschiedene Modi, die in Form eines 
  3365. Aufzählungstyps versteckt in "ios" definiert werden:
  3366. enum seek_dir
  3367. {
  3368.     beg = -1, // absolute Position zum Dateianfang
  3369.     cur = 0,        // relative Verschiebung von der akt. 
  3370. Position
  3371.     end = 1   // (negativer) Offset zum Dateiende
  3372. }
  3373.  
  3374. Das folgende Programm macht dem Rechner ein "x" für ein 
  3375. "u" vor, indem es in einer Datei alle "u" und "U" durch 
  3376. "x" bzw. "X" ersetzt. Dazu braucht man natürlich ein 
  3377. "fstream"-Objekt, denn man muß ja gleichermaßen lesen (um 
  3378. die "U""s zu suchen) und schreiben (nämlich die "X"-e). 
  3379. Die Datei wird hier zeichenweise eingelesen, und immer, 
  3380. wenn ein "U" gefunden wurde, wird die Position mit "seekg" 
  3381. um ein Zeichen zurückgesetzt und dann eben dieses "U" 
  3382. überschrieben: 
  3383.  
  3384. #include <fstream.h>
  3385.  
  3386. const char name[ ] = "ram:test";
  3387.  
  3388. void main()
  3389. {
  3390.     fstream f(name, ios::in|ios::out);
  3391.  
  3392.     while (f)
  3393.     {
  3394.         char c = f.get();                     // Zeichen lesen
  3395.  
  3396.         if (c == «u« || c == «U«)             // "U" ?
  3397.         {
  3398.             f.seekg(-1, ios::cur);                // dann zurück
  3399.             f.put( c=="u" ? «x« : «X« );          // und "X" schreiben
  3400.         }
  3401.     }
  3402. }
  3403.  
  3404. Als letztes lernen Sie jetzt noch eine Funktion kennen, 
  3405. mit der Sie die aktuelle Dateiposition ermitteln können. 
  3406. Sie heißt "tellg":
  3407. long fstreambase::tellg ()
  3408.  
  3409. und liefert, wenn sie auf einem "ifstream"-, "ofstream"- 
  3410. oder "fstream"-Objekt aufgerufen wird, die Position 
  3411. bezüglich des Dateianfangs in Bytes. Die erste Position 
  3412. hat wie immer die Nummer Null.
  3413.  
  3414. 2.3 Ein paar wichtige Definitionen in <new.h>
  3415. In der Datei "<new.h>" steht eigentlich fast nichts: Zum 
  3416. einen wäre da der Datentyp "size_t", der mit "unsigned" 
  3417. identisch ist und auch in diversen anderen Files definiert 
  3418. wird, außerdem die hinlänglich bekannte Konstante "NULL" 
  3419. und die folgende Funktion:
  3420. void (*set_new_handler(void(*)(void))) (void)
  3421.  
  3422. Man muß natürlich dreimal hinsehen, um diese Deklaration 
  3423. als Funktion zu erkennen. Einfacher wird"s, wenn man die 
  3424. Deklaration mit einem "typedef" aufteilt:
  3425. typedef void (*ftype) (void);
  3426. ftype set_new_handler (ftype);
  3427.  
  3428. Also erwartet die Funktion "set_new_handler" als Argument 
  3429. einen Zeiger auf eine Funktion, die weder Parameter noch 
  3430. Ergebnistyp hat, und gibt auch einen solchen zurück. Sinn 
  3431. und Zweck dieser Funktion ist es, eine Handler-Funktion zu 
  3432. setzen, die Speichermangel bei "new" oder "malloc" 
  3433. handhabt.
  3434. Normalerweise ignoriert es die Laufzeitbibliothek, wenn 
  3435. bei "new" oder "malloc" kein Speicher angefordert werden 
  3436. konnte, und liefert dann lediglich einen Nullzeiger, mit 
  3437. dem das Programm dann gefälligst selbst klarkommen muß. 
  3438. Rein praktisch bedeutet das, daß hinter jedes "new", 
  3439. "malloc", "calloc" usw. so etwas wie eine "if"-Abfrage 
  3440. gehört, die eine solche fehlgeschlagene 
  3441. Speicheranforderung abfängt und das Programm dann 
  3442. irgendwie sinnvoll weiterführt oder sauber beendet.
  3443. Bequemer kann man dieses lösen, indem man mit 
  3444. "set_new_handler" eine Funktion setzt, die in Zukunft 
  3445. immer dann aufgerufen wird, wenn der Speicher nicht 
  3446. ausreicht. Nach Ausführung dieser Funktion (sofern dort 
  3447. nicht mit "exit" o. ä. ausgestiegen wird) versucht die 
  3448. Bibliothek noch einmal, den benötigten Speicher 
  3449. anzufordern, und ruft im Mißerfolgsfall erneut den Handler 
  3450. auf.
  3451. Wählt man einen Nullzeiger als Argument für 
  3452. "set_new_handler", ist wieder die Standard-Einstellung 
  3453. aktiv, d. h. das System kümmert sich nicht weiter um den 
  3454. Speicherüberlauf. Das Ergebnis von "set_new_handler" ist 
  3455. in jedem Fall die bisher gültige Einstellung, also ein 
  3456. Zeiger auf eine zuvor gesetzte Handlerfunktion oder eben 
  3457. Null.
  3458. Die Funktion "set_new_handler" wird auch in Abschnitt 
  3459. 2.6.6 des C++-Tutorials erläutert. Das folgende 
  3460. Beispielprogramm fordert gnadenlos so lange Speicherblöcke 
  3461. an, bis der Handler "coredumped" aufgerufen wird.
  3462. #include <new.h>
  3463. #include <stream.h>
  3464.  
  3465. unsigned MemUsed = 0;
  3466.  
  3467. void coredumped()
  3468. {
  3469.     cout Ç "Speicherüberlauf nach " Ç MemUsed Ç " Bytes.\n";
  3470.     cout Ç "Programm steigt aus!!!\n";
  3471.     exit(42);
  3472. }
  3473.  
  3474. void main()
  3475. {
  3476.     const unsigned int size = 10000;
  3477.  
  3478.     set_new_handler(coredumped);
  3479.  
  3480.     for(;;)
  3481.     {
  3482.         char *cp = new char[size];
  3483.         MemUsed += size;
  3484.     }
  3485. }
  3486.  
  3487.  
  3488.  
  3489. __MEMFLAGS
  3490.  
  3491. extern unsigned int __MEMFLAGS;
  3492.  
  3493.     Beim Operator "new" und in den C-Funktionen "malloc", 
  3494. "calloc" usw. wird stets beliebiger Speicher alloziert und 
  3495. mit Nullbytes gefüllt. Dieses Verhalten kann man aber 
  3496. ändern: Die Variable "__MEMFLAGS" enthält die Flags, die 
  3497. von der Standardbibliothek an die Exec-Funktion "AllocMem" 
  3498. übergeben werden. Standardmäßig ist diese Variable mit dem 
  3499. Wert 0x10000, also "MEMF_CLEAR", initialisiert.
  3500.     Wenn Sie mit MaxonC++ ein Programm entwickeln, daß später 
  3501. auch auf anderen Computern und Compilern laufen soll, 
  3502. sollten Sie unbedingt am Anfang ihres Programms 
  3503. "MEMF_CLEAR" auf Null setzen, um so die Initialisierung 
  3504. des reservierten Speichers mit Nullbytes zu unterdrücken, 
  3505. und vielleicht noch zusätzlich ein Tool wie "MungWall" 
  3506. verwenden. Dann können Sie sicher sein, daß diese kleine 
  3507. Inkompatiblität Ihnen beim Portieren keine Probleme 
  3508. bereiten wird.
  3509.     Eine andere denkbare Anwendung von "__MEMFLAGS": Wenn Sie 
  3510. hier eines der Flags wie "MEMF_CHIP" oder "MEMF_PUBLIC" 
  3511. eintragen, können Sie die Speicherklasse der nachfolgenden 
  3512. "new"- oder "malloc"-Aufrufe festlegen.
  3513.  
  3514. 2.4 Ausnahmebehandlung: $$exception.h>
  3515.  
  3516. class Exception
  3517.  
  3518.    class Exception
  3519.     { public:
  3520.         virtual ~Exception() { }
  3521.     };
  3522.  
  3523.     Wie im Tutorial in Kapitel 8.3 schon angedeutet, greift 
  3524. die Klasse "Exception" dem sehnlichst erwarteten ANSI 
  3525. C++-Standard vor und definiert eine Basisklasse für alle 
  3526. Ausnahmen. Wenn Sie Klassen für Ihre Ausnahmen definieren, 
  3527. können Sie die von dieser Klasse ableiten - müssen Sie 
  3528. aber nicht.
  3529.  
  3530. unexpected
  3531.  
  3532. void unexpected();
  3533.  
  3534.     Diese Funktion wird aufgerufen, wenn in erier Funktion it 
  3535. Ausnahme-Deklaration eine unerwartete Exception geworfen 
  3536. wird (siehe auch Tutorial 8.6). Normalerweise wird man sie 
  3537. nicht "von Hand" aufrufen.
  3538.     "unexpected" ruft die zuletzt mit "set_unexpected" 
  3539. gesetzte Funktion auf. Default ist "terminate".
  3540.  
  3541. terminate
  3542.  
  3543. void terminate();
  3544.  
  3545.     "terminate" wird normalerweuse nur von "unexpected" 
  3546. aufgerufen und enthält selbst nur einen Sprung an die 
  3547. zuletzt mit "set_terminate" gesetzte Funktion, was 
  3548. defaultmäßig "abort" ist.
  3549.  
  3550. set_unexpected
  3551.  
  3552. Definiton: void (*set_unexpected(void(*)()))();
  3553.  
  3554.     Wie oben bereits erwähnt, kann man mit "set_unexpected" 
  3555. festlegen, in welche Funktion "unexpected" einspringen 
  3556. soll. Als Ergebnis wird die bisher gültige Funktion 
  3557. zurückgegeben.
  3558.  
  3559. set_terminate
  3560.  
  3561. void (*set_terminate(void(*)()))();
  3562.  
  3563.     Analog zu "set_unexpected" verändert diese Funktion das 
  3564. Verhalten von "terminate". Lesen Sie dazu auch das Kapitel 
  3565. 8.6 im Tutorial.
  3566. 2.5 Eine String-Library: <tools/str.h>
  3567. 2.5.1 Die Klasse "String"
  3568. Im Unterverzeichnis "tools", das für Hilfsbibliotheken 
  3569. aller Art vorgesehen ist, finden Sie eine Datei "str.h", 
  3570. die Ihnen eine C++ angemessene Stringverwaltung beschert.
  3571. Im wesentlichen wird dort eine Klasse namens "String" 
  3572. deklariert, die dynamische Zeichenketten repräsentiert. 
  3573. Das bedeutet: Man deklariert lediglich eine Variable des 
  3574. Typs "String", und die Bibliothek sorgt selbst dafür, daß 
  3575. stets genug - und, einmal abgsehen von einem gewissen 
  3576. Overhead, auch nie zuviel - Speicher dafür reserviert 
  3577. wird. Im Tutorial wird in Kapitel 4.2.3 eine ähnliche 
  3578. (aber weniger leistungsfähige) Library als 
  3579. Beispielprogramm vorgestellt und implementiert.
  3580. Die Klasse "String" besitzt vier verschiedene 
  3581. Konstruktoren:
  3582. String (const char *s = 0)
  3583. String (int l, char *s)
  3584. String (const String &S)
  3585. String (char c)
  3586.  
  3587. Der erste Konstruktor initialisiert einen String mit einer 
  3588. Zeichenkette (oder dem Leerstring als Default) und dürfte 
  3589. der bei Variablendeklarationen meistgebrauchte sein, z. B.
  3590. String s1, s2 = "Horrido!", s3 = 0, s4 = "";
  3591.  
  3592. Hier werden die Variablen "s1", "s3" und "s4" jeweils als 
  3593. Leerstrings initialisiert, während in "s2" die 
  3594. Zeichenkette "Horrido!" abgespeichert wird. Dazu muß der 
  3595. Konstruktor natürlich Speicher anfordern und dies in "s2" 
  3596. vermerken. Um solchen Speicher wieder freizugeben, wenn 
  3597. die Stringvariable nicht mehr existiert, besitzt die 
  3598. Klasse "String" auch einen Destruktor.
  3599. Den zweite Konstruktor benötigt man hauptsächlich, wenn 
  3600. man der Bibliothek eigene Stringfunktionen hinzufügen 
  3601. will. Aus einem "char[ ]"-Objekt, das mit "new" erzeugt 
  3602. worden sein muß und mit einem String, der ausschließlich 
  3603. des abschließenden Nullbytes die Länge "l" hat, 
  3604. initialisiert sein muß, wird hier ein "String"-Objekt 
  3605. erzeugt. Dabei wird die Zeichenkette "s" nicht noch einmal 
  3606. kopiert, sondern der Zeiger darauf direkt in das 
  3607. Stringobjekt eingetragen.
  3608.  
  3609. Der dritte Konstruktor ist, wie man sieht, ein 
  3610. Copy-Konstruktor, und der letzte initialisiert das Objekt 
  3611. mit einem Zeichen, das als Zeichenkette der Länge "1" 
  3612. interpretiert wird. Damit sind
  3613. String s1 = "?"
  3614.  
  3615. und
  3616. String s1 = «?«
  3617.  
  3618. mehr oder weniger äquivalent.
  3619.  
  3620. 2.5.2 Member-Funktionen
  3621. Mit den oben aufgeführten Konstruktoren gibt es eine 
  3622. Konvertierung von den ordinären Zeichenvektoren, mit denen 
  3623. sich der C-Programmierer herumschlagen muß, in die 
  3624. Stringklasse. Für Kompatibilität in die andere Richtung 
  3625. sorgt die Konvertierungsfunktion
  3626. String::operator char*() const
  3627.  
  3628. Sie wandelt ein "String"-Objekt in einen Zeiger auf eine 
  3629. Zeichekette um. Dabei sollte man sich aber hüten, diese 
  3630. Konvertierung auf temporäre Objekte anzuwenden, z. B. auf 
  3631. das Ergebnis der unten vorgestellten Operatorfunktion "+", 
  3632. denn natürlich liefert sie lediglich einen Zeiger auf den 
  3633. ansonsten "geheimen" Speicherbereich, in dem der 
  3634. eigentliche Wert des Stringobjekts abgespeichert wird, und 
  3635. wenn die Stringvariable nicht mehr existiert oder einen 
  3636. neuen Wert zugewiesen bekommt, muß man stets damit 
  3637. rechnen, daß dieser Speicherbereich freigegeben und wieder 
  3638. überschrieben wird.
  3639. Es gibt zwei Zuweisungsoperatoren:
  3640. String & String::operator = (const String &S)
  3641. String & String::operator = (const char *s)
  3642.  
  3643. Die erste Funktion funktioniert, wie Sie sich denken 
  3644. können, analog zum Kopier-Konstruktor, gibt aber den 
  3645. Speicher, der für den bisherigen Variablenwert alloziert 
  3646. wurde, wieder frei. Die zweite ist eigentlich redundant, 
  3647. denn der Compiler ist natürlich durchaus clever genug, bei 
  3648. einer Wertzuweisung wie
  3649. String s1;
  3650. char c[ ] = "Frood";
  3651.  
  3652. s1 = c;
  3653.  
  3654. aus dem Zeichenvektor mit Hilfe des entsprechenden 
  3655. Konstruktors ein temporäres Objekt zu erzeugen und dieses 
  3656. dann mit der erstgenannten "="-Funktion in das Zielobjekt 
  3657. zu kopieren. Mit dieser zusätzlichen Funktion wird dies 
  3658. aber deutlich abgekürzt.
  3659. Ungefähr wie "strcat" in Standard-C, nur eben erheblich 
  3660. bequemer, funktioniert die Member-Funktion
  3661. String & String::operator += (const String &s),
  3662.  
  3663. die zwei Strings aneinander hängt: Nach
  3664. String s1 = "Moin ", s2 = "Moin!";
  3665.  
  3666. s1 += s2;
  3667.  
  3668. hat "s1" den Wert "Moin Moin!".
  3669. Sie wollen auf einen String zeichenweise zugreifen? Null 
  3670. Problemo, auch das geht, und zwar mit der folgenden 
  3671. Operator-Funktion:
  3672. char String::operator[ ] (int i) const
  3673.  
  3674. Sie liefert als Ergebnis das "i"-te Zeichen einer 
  3675. Stringvariablen, allerdings nicht als Referenz und damit 
  3676. auch nicht als L-Wert. Deshalb kann man mit Indizierung 
  3677. Zeichen aus einem String auslesen, aber keine einzelnen 
  3678. Zeichen verändern. Dies wurde aus Sicherheitsgründen so 
  3679. eingerichtet.
  3680. Um die Länge eines Strings festzustellen, können Sie die 
  3681. Standard-Funktion "strlen" benutzen, denn es existiert ja 
  3682. eine Konvertierung von "String" nach "char*". Angenehmer 
  3683. und schneller ist aber die folgende Member-Funktion:
  3684. int String::length() const
  3685.  
  3686. Sie liefert die Länge eines Strings, wobei das Nullbyte am 
  3687. Ende wie immer nicht mitgezählt wird. Aufgerufen wird sie 
  3688. natürlich in der Form
  3689. i = s1.length();
  3690.  
  3691. Zu guter Letzt wären da noch drei Funktionen, die 
  3692. irgendwie an alte BASIC-Tage erinnern:
  3693. String String::left (int n) const
  3694. String String::right (int n) const
  3695. String String::mid (int pos, int n) const
  3696.  
  3697. "left" liefert die ersten "n" Zeichen eines Strings, 
  3698. "right" die letzten "n". Falls der String kürzer als "n" 
  3699. ist, ist das Ergebnis mit dem Argument identisch. "mid" 
  3700. nimmt aus einem String "n" Zeichen ab der Position "pos", 
  3701. wobei letztere wie immer von Null an gezählt wird.
  3702.  
  3703.  
  3704. 2.5.3 Der Operator "+" auf Strings
  3705. Das waren alle Funktionen, die als Member von "String" 
  3706. deklariert sind. Daneben gibt es noch einige global 
  3707. deklarierte Operatorfunktionen:
  3708. Die angenehmste ist sicherlich
  3709. String operator + (String s1, String s2)
  3710.  
  3711. Dieses "+" hängt, wie man es auch nicht anders erwartet, 
  3712. zwei Strings aneinander. Anders als bei "strcat" oder dem 
  3713. Operator "+=" werden hier die Werte der Argumente 
  3714. keineswegs verändert, sondern es wird ein neues 
  3715. (temporäres) Objekt erzeugt, falls das Ergebnis nicht 
  3716. sogar direkt in das gewünschte Ziel geschrieben wird.
  3717. Da es sonst keine Addition auf Standard-Strings (d. h. 
  3718. char-Zeigern) gibt, kann dieser neue Plus-Operator auch 
  3719. dort angewendet werden:
  3720. #include <tools/str.h>
  3721. #include <stream.h>
  3722.  
  3723. void main()
  3724. {    char *s1 = "Grunz",
  3725.     *s2 = s1 + "wanzling";
  3726.  
  3727.     cout Ç s2;
  3728. }
  3729.  
  3730. Eigentlich ist dieses Beispiel korrekt, denn bei der 
  3731. Addition wird der "+"-Operator aus der String-Bibliothek 
  3732. benutzt und dessen Ergebnis, ein temporäres Objekt der 
  3733. Klasse "String", mit der Konvertierungsfunktion nach 
  3734. "char*" gewandelt. Dabei wird aber der alte Fehler 
  3735. begangen, einen Zeiger auf ein temporäres Objekt zu 
  3736. verwenden. Wenn "s2" ausgegeben wird, existiert das 
  3737. temporäre Objekt (und mit ihm sein Zeichenvektor) schon 
  3738. lange nicht mehr, und die Ausgabe ist undefiniert.
  3739. So hätte es natürlich geklappt:
  3740. #include <tools/str.h>
  3741. #include <stream.h>
  3742.  
  3743. void main()
  3744. {    char *s1 = "Grunz";
  3745.     String s2 = s1 + "wanzling";
  3746.  
  3747.     cout Ç s2;     // Ausgabe für "String" existiert - siehe 
  3748. unten
  3749. }
  3750.  
  3751. Hier wird - je nach Compiler - die String-Summe entweder 
  3752. gleich im Zielobjekt "s2" konstruiert, oder das hier 
  3753. eingeführte temporäre Objekt wird mit dem Copy-Konstruktor 
  3754. in "s2" übertragen, bevor es destruiert wird. Also 
  3755. funktioniert "+" hier so, wie man es erwartet.
  3756. Deshalb soll hier noch einmal erwähnt werden, daß die 
  3757. Konvertierungsfunktion von "String" nach "char*" nur mit 
  3758. Vorsichtig und Bedacht zu benutzen ist, denn andernfalls 
  3759. erlebt man Überraschungen.
  3760.  
  3761. 2.5.4 Vergleiche
  3762. Natürlich kann man String-Objekte mit der Funktion 
  3763. "strcmp" vergleichen. Mit den folgenden Operatoren geht 
  3764. das aber wesentlich bequemer:
  3765. int operator == (const String &s1, const String &s2)
  3766. int operator != (const String &s1, const String &s2)
  3767. int operator <  (const String &s1, const String &s2)
  3768. int operator >  (const String &s1, const String &s2)
  3769. int operator <= (const String &s1, const String &s2)
  3770. int operator >= (const String &s1, const String &s2)
  3771.  
  3772. Die beiden Operanden werden jeweils wie mit "strcmp" 
  3773. verglichen (ASCII-Reihenfolge), und das Ergebnis ist ein 
  3774. boolscher Wert.
  3775. Ein Mini-Beispiel:
  3776. #include <tools/str.h>
  3777. #include <stream.h>
  3778.  
  3779. void main()
  3780. {    String s1 = "Test", s2 = "Text";
  3781.  
  3782.     if (s1 < s2)
  3783.         cout Ç s1;
  3784.     else
  3785.         cout Ç s2;
  3786. }
  3787.  
  3788. Ein kleiner Wermutstropfen: Vergleiche wie
  3789. String s1;
  3790.  
  3791. if(s1 == "Nanu?") ...
  3792.  
  3793. sind nicht erlaubt, da mehrdeutig! Schließlich gibt es 
  3794. sämtliche Vergleichsoperationen auch auf Zeigern (und 
  3795. insbesondere Zeichenketten), und so weiß der Compiler oben 
  3796. nicht, ob er "s1" nach "char*" konvertieren und diese 
  3797. Adresse dann mit der des Strings "Nanu?" vergleichen, oder 
  3798. ob er aus der konstanten Zeichenkette mittels 
  3799. Konstruktoraufruf ein temporäres "String"-Objekt erzeugen 
  3800. und darauf den String-Operator "==" anwenden soll.
  3801. So geht"s aber:
  3802. if (s1 == String("Nanu?"))
  3803.  
  3804. 2.5.5 Ein- und Ausgabe
  3805. In den obigen Beispielen wurden mehrfach Objekte der 
  3806. Klasse "String" ausgegeben. Das ist ohne weiteres möglich, 
  3807. denn die Operatoren wurden - wie im Tutorial unter 
  3808. Abschnitt 4.2.2.7 beschrieben - entsprechend zusätzlich 
  3809. überladen:
  3810. class ostream& operator Ç (ostream&, const String&)
  3811.  
  3812. class istream& operator È (istream&, String&)
  3813.  
  3814. Die Ein- und Ausgabe von "String"-Objekten funktioniert 
  3815. damit genau wie die von gewöhnlichen 
  3816. "char*"-Zeichenvektoren.
  3817.  
  3818.  
  3819. 2.6 Interna von MaxonC++: <streamdefs.h>
  3820. Jeder hat so seine kleinen Geheimnisse - aber MaxonC++ 
  3821. verrät sie hemmungslos. Na ja, zumindest gibt es in der 
  3822. Datei "<streamdefs.h>" einige Definitionen, die über die 
  3823. interne Organisation der Dateiverwaltung von MaxonC++ 
  3824. Aufschluß geben.
  3825. In "<stdio.h>" wird der enorm wichtige Datentyp "FILE" 
  3826. definiert, der nichts als ein Alias für "struct stream" 
  3827. darstellt. Dieser Strukturtyp wird in "<streamdefs.h>" 
  3828. definiert, und zwar wie folgt:
  3829. struct stream
  3830. {    unsigned Filehandle;
  3831.     char UngetCh, UngetBuf;
  3832.     signed char Mode, Error;
  3833.     struct streambuffer *bufptr;
  3834.     struct    {
  3835.         int f_freemem:1,
  3836.         f_closefile:1
  3837.         }    flags;
  3838. };
  3839.  
  3840. Die Felder haben folgende Bedeutung:
  3841.     Filehandle:    Dies ist die AmigaDOS-Filehandle, die zur 
  3842. Datei gehört.
  3843.     UngetCh:    Ein Flag, das anzeigt, ob ein Zeichen mit 
  3844. "ungetc" zurückgestellt wurde.
  3845.     UngetBuf:    Der Puffer, in dem eben jenes Zeichen abgelegt 
  3846. wird.
  3847.     Mode:    In diesem Byte steht ist das Bit #0 gesetzt, wenn 
  3848. die Datei zum Lesen geöffnet wurde, und Bit #1 steht 
  3849. entsprechend für Schreibzugriffe.
  3850.     bufptr:    Wenn dieser Zeiger nicht Null ist, zeigt er auf 
  3851. eine "streambuffer"-Struktur, in der Informationen über 
  3852. das Puffern der Datei enthalten sind.
  3853.     flags:    Das Bit "f_freemem" (Nummer 7) dieses Byte-großen 
  3854. Bitvektors zeigt an, ob "fclose" die "stream"-Struktur aus 
  3855. einer gewissen internen Liste aushängen soll, und 
  3856. "f_closefile" wird gesetzt, wenn bei "fclose" die 
  3857. DOS-Datei "Filehandle" geschlossen werden soll.
  3858. Die Struktur "streambuffer" wird normalerweise von den 
  3859. Funktionen "setvbuf" oder "setbuf" erzeugt und in die 
  3860. "stream"-Struktur eingehängt. Sie ist folgendermaßen 
  3861. aufgebaut:
  3862. struct streambuffer
  3863. {    stream *streamptr;
  3864.     short size, fill, pos;
  3865.     signed char mode, own;
  3866.     int (*read)(register streambuffer *a0, register void *d2,
  3867.          register unsigned d3);
  3868.     int (*write)(register streambuffer *a0, 
  3869.         register void *d2, register unsigned d3);
  3870.     int (*flush)(register streambuffer *a0);
  3871.     int (*close)(register streambuffer *a0);
  3872.     void *buf;
  3873. };
  3874.  
  3875. Die Bedeutung der Member:
  3876.     streamptr:    Ein Rückverweis auf die "stream"-Struktur, 
  3877. deren Zeiger "bufptr" wiederum auf diese 
  3878. "streambuffer"-Strukt ur zeigt.
  3879.     size:    Puffergröße (in Bytes)
  3880.     fill:    Anzahl der momentan benutzten Puffer-Bytes
  3881.     pos:    Bei Lesepuffern die aktuelle Leseposition
  3882.     mode:    Ist positiv, wenn es sich um einen Schreibpuffer 
  3883. handelt, negativ, wenn der Puffer zum Lesen dient, und 
  3884. Null, wenn der Puffer aus irgendwelchen Gründen überhaupt 
  3885. nicht benutzt werden soll.
  3886.     own:    Ein Flag, das gesetzt wird, wenn "setvbuf" den für 
  3887. den Puffer "buf" benötigten Speicher selbst alloziert hat. 
  3888. Dadurch weiß die Laufzeitbibliothek beim Schließen der 
  3889. Datei, ob der Speicherbereich, auf den "buf" zeigt, 
  3890. freigegeben werden muß.
  3891.     read:     Ein Zeiger auf eine Funktion mit den angegebenen 
  3892. Register-Parametern. Sie wird bei Eingaben aus der 
  3893. gepufferten Datei aufgerufen und sollte sich wie die 
  3894. AmigaDOS-Funktion "Read" verhalten, einmal davon 
  3895. abgesehen, daß das erste Argument hier keine Filehandle, 
  3896. sondern ein Zeiger auf den "streambuf" ist und auch nicht 
  3897. in "d1", sondern in "a0" übergeben wird.
  3898.     write:    Die entsprechende Funktion für Ausgaben in Dateien.
  3899.     flush:    Ebenfalls ein Zeiger auf eine Funktion. Sie wird 
  3900. (wie man sich denken kann) aufgerufen, wenn auf der Datei 
  3901. "fflush" ausgeführt wird oder wenn sie geschlossen wird.
  3902.     close:    Diese Funktion wird beim Schließen der Datei 
  3903. aufgerufen und sollte insbesondere den vom Puffer belegten 
  3904. Speicher freigeben. Falls die "streambuffer"-Struktur 
  3905. dynamisch erzeugt wurde, sollte die "close"-Funktion auch 
  3906. diese löschen.
  3907.     buf:    Ein Zeiger auf den eigentlichen Puffer.
  3908.  
  3909. Die Sache mit diesen Zeigern auf Funktionen hätte man 
  3910. natürlich viel eleganter und einfacher mit Vererbung und 
  3911. virtuellen Memberfunktionen realisieren können, aber die 
  3912. Definitionen sollten auch im ANSI C-Modus benutzt werden 
  3913. können. Es steht dem Programmierer natürlich frei, diesen 
  3914. Definitionen einen objektorientierten Ansatz zu 
  3915. überlagern, so wie in "stream.h" das C++-typische 
  3916. Stromkonzept auf die ANSI-Dateiverwaltung aufgesetzt wird.
  3917. Was soll das ganze eingentlich? Nun, mit diesen 
  3918. Informationen (und vielleicht ein wenig Herumprobieren) 
  3919. ist es möglich, eigene Routine auf tiefem Niveau in die 
  3920. Ein-/Ausgaberoutinen der Maxon C++ Laufzeitbibliothek zu 
  3921. integrieren. Es ist ja nicht gesagt, daß eine Struktur 
  3922. "streambuffer" immer nur einen Puffer repräsentiert. 
  3923. Beispielsweise könnte man hier Routinen einhängen, die 
  3924. Ein- und Ausgaben in Intuition-Windows machen, und dann z. 
  3925. B. mit "printf" in einen Dialogfenster schreiben. Der 
  3926. Phantasie sind hier fast keine Grenzen gesetzt.
  3927. Übrigens: Wenn hinter einem "stream" gar keine wirkliche 
  3928. DOS-Datei, sondern ein "streambuffer" mit 
  3929. selbstgeschriebenen geheimnisvollen Funktionen steht, 
  3930. sollte man den Member "Filehandle" auf Null setzen. Dann 
  3931. wissen Funktionen wie "fseek" oder "ftell" Bescheid und 
  3932. versuchen erst gar nicht, auf dieser nicht existenten 
  3933. DOS-Datei zu operieren.
  3934. Um das Herumtrashen an der Dateiverwaltung zu erleichtern, 
  3935. gibt es die Funktion "allocstream":
  3936. stream *allocstream(unsigned Handle)
  3937.  
  3938. Sie erzeugt ein neues Objekt des Typs "stream", trägt 
  3939. "Handle" als Filehandle ein und vermerkt die Struktur in 
  3940. der internen Liste der Dateien. Dadurch wird der Strom z. 
  3941. B. am Dateiende automatisch geschlossen, und "fflush(0)" 
  3942. wirkt auch auf diesen Stream. Dementsprechend wird auch 
  3943. das Flagbit "f_freemem" gesetzt.
  3944. Falls nicht mehr genug Speicher für die Struktur frei ist, 
  3945. liefert "allocstream" wie üblich eine Null.
  3946.  
  3947.  
  3948. 2.6     Funktionen für originelle Linker-Optionen: 
  3949. <linkerfunc.h>
  3950. In der Include-Datei "<linkerfunc.h>" finden Sie einige 
  3951. MaxonC++-typische Funktionen, die Sie vor allem dann 
  3952. brauchen, wenn Sie ohne Startup-Code linken (siehe auch 
  3953. Abschnitt 4.6 des Benutzerhandbuchs).
  3954. Jede Objektdatei kann in C++ dynamische Initialisierungen 
  3955. benötigen, also eine Funktion besitzen, die beim 
  3956. Programmstart unbedingt aufgerufen werden muß. Außerdem 
  3957. kann es natürlich statische Daten geben, für die am 
  3958. Programmende Destruktoren aufgerufen werden müssen. Der 
  3959. Linker generiert Funktionen, in denen alle diese 
  3960. Initialisierungs- bzw. Aufräumfunktionen augerufen werden:
  3961. void InitModules()
  3962.  
  3963. ruft alle Initialisierungen auf, und
  3964. void CleanupModules()
  3965.  
  3966. die Destruktoren. Wenn man sich einen Startup-Code selbst 
  3967. schreibt, sollte man am Anfang auf jeden Fall 
  3968. "InitModules" und am Programmende "CleanupModules" 
  3969. aufrufen.
  3970. Es kommt bisweilen vor, daß eine C++-Funktion nicht aus 
  3971. einem C++-Programm, sondern von irgendwoher aufgerufen 
  3972. wird, z. B. wenn man eine Shared Library in C++ 
  3973. geschrieben hat. Das gibt natürlich Probleme, wenn man in 
  3974. seiner Funktion "Small Data" verwendet, denn dann vertraut 
  3975. die Funktion darauf, daß im Register A4 ein Zeiger auf den 
  3976. Datenhunk steht.
  3977. Was tun? Nun, man muß diesen Zeiger explizit laden, indem 
  3978. man ganz am Anfang der Funktion (also, jedenfalls vor 
  3979. jeglichem Zugriff auf statische Daten)
  3980. void GetBaseReg()
  3981.  
  3982.