Juni 2021

Die zugehörige C-Quelle.

STRING – Ultimative String-Klasse in C

Beschreibung der Definitionen: Makros und Funktionen

Die definierten Makros und Funktionen für diese Strings erlauben vielfältige, flexible und hochgradig schnelle Operationen. Ein komfortabler, objektorientierter Umgang ist möglich.

Zum aktuellen Zeitpunkt sind noch nicht alle Funktionen realisiert. Es werden weitere Funktionen fortlaufend hinzugefügt werden. Dieses Dokument wird ebenso fortlaufend aktualisiert. Es ist bisher etwa eine Woche Entwicklungszeit im ersten Schub entstanden. Die C-Quelle ist stets eine vollständige Informationsquelle für alle Details.

Eine Verwendung von malloc() ist zumindest bis jetzt vermieden worden, da dies generell die Performance schädigt. Außerdem sind heutzutage Motherboards (Xeon) erhältlich, die mit bis zu 7 Terabyte RAM bestückt werden können. Normale PCs stehen heute meist bei 32 Gigabyte. Ein Stack-Limit (ulimit) lautet: 524 MB. Es kann folglich beim Anlegen von Datenobjekten relativ großzügig vorgegangen werden.

Der Typ size_t ist bei einer 64bit-Kompilierung 64 Bit breit und bei einer 32bit-Kompilierung 32 Bit breit. Dies unter Unix sowie auch unter Windows. Zu diesen Bit-Breiten sind jeweils auch Prozessor-Register vorhanden. Aus diesen Gründen wurde dieser Typ bei den grundlegenden Definitionen CTLTYP und CTLWID eingesetzt.

Der Quellcode dieser String-Klasse ist portabler interner Library-Code und muß auch als solcher betrachtet werden. Anwendungscode ist nur in den diversen Testfunktionen am Ende der Quelle vorhanden. Wichtig für den Anwender sind vor allem die Funktionsbeschreibungen unten in dieser Dokumentation.

Vorteile

Die Funktionen dieser String-Klasse sind absolut sicher. Ein Puffer-Überlauf ist konzeptionell ausgeschlossen. Bevor kopiert wird, wird berechnet, ob ein Überlauf beim Kopieren passieren würde. Falls ja, wird der Prozeß beendet. Eine teilweise Aktion, wie sie bei strncpy() möglich ist, ist nicht akzeptabel, da nachfolgende Operationen eine vollständige vorhergehende Aktion voraussetzen (müssen).

Diese Vorberechenbarkeit und die realisierten Vorberechnungen sind ein systematisches Konzept dieser String-Klasse. Dies gibt Sicherheit und hohe Arbeitsgeschwindigkeit, weil in Schleifen keine Prüfungen bei jedem Schritt notwendig sind, ob irgendeine Grenzenberührung stattfindet. Die Funktion stringmov() ist ein Parade-Beispiel dafür.

Es werden zwei auseinander positionierte MAGIC-Nummern auf Vorhandensein in jedem String-Objekt geprüft, in jeder relevanten Funktion. Zuvor wird auf Null-Pointer geprüft. Null-Pointer und nicht passende MAGIC-Nummern werden nicht akzeptiert. Ein String-Objekt muß sich gültig identifizieren.

Da das Konzept keinen Terminierungs-Wert vorsieht, dürfen diese Strings inhaltlich sämtliche Werte beliebig enthalten. Eine nachträgliche Null-Terminierung kann mittels der Funktion string0t() vorgenommen werden.

Neben der Länge len sind zusätzlich die Parameter Offset off und Breite wid vorhanden. Für alle drei Parameter sind dedizierte Funktionen zum Setzen des jeweiligen Wertes vorhanden. Die Länge gilt ab Offset. Deren Änderung ändert keine anderen Parameter. Erhöhung des Offsets verringert die Länge, und umgekehrt. Eine Änderung der Breite ändert Länge und Offset. Die Funktionen zum Setzen sind am String-Element (mit seiner Breite) orientiert, nicht am Byte.

Ein String-Objekt kann schreibgeschützt werden:  CNTLP(name)->ro = 1;
Anwenderfunktionen berücksichtigen dieses read_only. Der Schreibschutz gilt für den Inhalts-Puffer, nicht für den Kontrollbereich (CNTL).

Das String-Objekt, wie auch sein Puffer darin, sind AL-aligned (z.B. 16). Daher kann beispielsweise die Funktion stringcpy() stets die gesamte Kopiermenge in Stücken von AL Byte kopieren. Die Funktion stringcats() kopiert durch einen ultimativen Algorithmus ebenfalls in maximal großen Stücken.

Diese String-Klasse wurde getestet, indem diese Strings mit den normalen null-terminierten C-Strings verglichen wurden. Die Testfunktionen befinden sich in der C-Quelle. Plattform: X86_64, LP, CoreDuo-Prozessor 3333 MHz aus 2007, DDR2. Im Stack wurde jeweils 77 MB Speicherplatz alloziert und durch fortschreitendes Kopieren mit Daten gefüllt. Eine Füll-Geschwindigkeit von 2,9 GB/s 1-fach wurde erreicht. Resultat: Kopieren mit dieser String-Klasse ist 1,44-mal schneller als mit den normalen C-Strings.
Das ist ein relativ geringer Vorsprung, was daran liegt, daß die C-Strings seit Ende der 1980er Jahre kontinuierlich immer weiter verbessert wurden. Es werden bis zu 8 Byte breite Objekte im Zusammenhang mit allerlei Tricks verwendet.
Ein Einfluß des Wertes von AL auf die Kopier-Geschwindigkeit konnte auf dieser Plattform nicht festgestellt werden. Es scheint da eine Deckelung zu wirken; Schneller geht es offenbar nicht.

Konzept · Layout

Angelegt wird ein uchar  array[ne]; mit festgelegten Typ, Name und Größe.
Die Objektgröße sizeof(array)-MAXWID in Byte wird beim Initialisieren in der ersten Kontroll-Komponente size gespeichert.
CNTL = offsetof(STRING,buf) .
Für den Puffer bleiben die Bytes BUF = size-CNTL übrig.
Variabel sind Anzahl Elemente und Elementbreite (len, wid):
bufsize = len*wid;  len = bufsize/wid;  wid = bufsize/len;

Das angelegte array[ne] besteht aus folgenden Komponenten:  s+8+o+l+BUF

  size + 8×Byte + offset + length + BUFFER
  8 + 8 + 8 + 8 Byte | 4 + 8 + 4 + 4 Byte
  # define ACHT mag1, wid, shft, swid, cntl, _5, filc, mag2
  typedef struct { CTLTYP size; uchar ACHT; CTLTYP off, len; XT buf; } STRING;
  typedef struct { uchar sign:1,text:1,lfil:1,ofil:1,ro:1,_5:1,_6:1,_7:1; } CNTLB;

Der Puffer kann 8  # Byte groß sein. Eines der 8 Bytes (cntl) besteht aus einem Bitfeld mit 8 Steuerbits (CNTLB). Das Makro CNTLP ist für den bequemen und konsistenten Zugriff auf die Steuerbits vorhanden. Gleichzeitiger Zugriff per Bitfeld (struct) und mittels Bit-Operationen passen nicht mehr zusammen nach Änderung der Endianness! Der Typ XT ist ein union-Typ mit mehreren verschiedenen Typen darin. Die roten Punkte stehen für _Alignas(AL).

Die Kontrollkomponenten size, off und len müssen (hier) nicht (mehr) näher erklärt werden. Puffer buf.xx[] ebenso nicht. Die Kontroll-Bytes mag1 und mag2 enthalten die beiden MAGIC-Zahlen. Erklärung unten bei den Funktionen. Das Byte wid enthält die Breite der Array-Elemente in Byte: sizeof(array[0]). Dies ist eine Potenz von 2. Dazu gehört shft, um Division und Multiplikation per Schiebe-Instruktion zu ermöglichen. Byte swid kann die Breiten von Strings {L|u|U|u8}"..." und Multibyte-Zeichen (1) enthalten. Byte cntl ist ein Bitfeld und oben und nachfolgend eingehend erklärt. Das Füllzeichen filc wird benutzt, um bei Operationen mit Länge und Offset entstehenden Leerraum zu füllen. Erklärung unten bei den Funktionen.
Die Steuerbits lfil und ofil entscheiden über das Füllen des im Byte filc enthaltenen Füllzeichens, im Zusammenhang mit Längen- und Offsetoperationen. Die Bedeutung der Bits sign und text dürfte klar sein. Aktuell ist text ohne Verwendung. Der Bit-Name ro steht für read_only und ist ein Schreibschutz für den Inhalts-Puffer eines String-Objekts. Erklärung auch oben. Die Bits text und ofil werden initial auf 1 gesetzt.

Definitionen · Test-Code

Es kann ein Strukturtyp STRING mit flexibler Array-Komponente[1] mit dem angelegten array[ne] verknüpft werden. STRING *sp gleicht dem bekannten FILE *fp. Dies wird in main() gezeigt. Ebenso gezeigt werden Anwendungen mit den Makros STRINGP und CNTLP.

Die Formulierung  STRING *sp= (STRING*)arrayname;  verknüpft den Typ STRING* mit einem uchar array[ne]. Die effektive Adresse ist die vom Array, das der Struktur STRING untergeschoben wurde. Das ist genau so, wie hier:  d_name[1] , als es das flexible array[] des C-Standards C99 noch nicht gab.
Ein flexibles Array des C99 kann in einer union nicht verwendet werden, weshalb es sein könnte, daß der Compiler Fehler gibt, falls eine sichtbare Konstante als Array[index] verwendet wird. Eine Alternative wären mehrere Strukturen mit jeweils flexibler Array[]-Komponente darin, innerhalb einer union. Die Ansprache im Code wäre dann jedoch sehr unhandlich.

Die Funktion main() zeigt Test-Operationen. Es sind die beiden Methoden des Anlegens von String-Objekten gezeigt: Außerhalb und innerhalb von Funktionen, jeweils ohne und mit dem Speicherklassen-Spezifizierer static. Das Makro STRING_DuI() kann nur innerhalb einer Funktion angewandt werden; Es nimmt Definition und Initialisierung gleichzeitig vor. Ein Anlegen mittels des Makros STRING_DEF() erfordert anschließend die Benutzung des Initialisierungs-Makros STRING_INI() innerhalb einer Funktion. String-Objekte können beliebig oft initialisiert werden.

Die Größenangabe bei den Makros() ist eine Anzahl Bytes, wie auch bei der Funktion malloc(). Dementsprechend kann eine Angabe beispielsweise (name,4*1000) oder (name,sizeof(int)*1000) lauten.

 Aktuelle Ausgabe der Funktion main() :
a:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
'a:100'
ziel:ifuiyg3qwruqiweidwgh2rhb
b:ifuiyg3qwruqiweidwgh2rhb
'b:24'
        ziel:   size=232        len=24  off=0   wid=1
        quelle: size=184        len=24  off=0   wid=1
        ziel:   size=232        len=24  off=0   wid=1
        cat:    size=536        len=48  off=0   wid=1
cat:ifuiyg3qwruqiweidwgh2rhbifuiyg3qwruqiweidwgh2rhb
'c:536'-d:48-
        file:   size=1032       len=96  off=0   wid=1
file:ifuiyg3qwruqiweidwgh2rhbifuiyg3qwruqiweidwgh2rhbifuiyg3qwruqiweidwgh2rhbifuiyg3qwruqiweidwgh2rhb
'e:1032'-f:96-
1056 1048 64 32

Makros

Es gibt recht viele Makros stringxxx(), die alle den Bezeichner eines String-Objektes als einziges Argument benötigen. Makros mit eingeklammertem Inhalt sind read-only. Die anderen sind lesbar und beschreibbar. Diese Makros sind vielfältig in den Funktionen eingesetzt.

stringbuf( name)
Die Basisadresse des angelegten Arrays, die ja in einen Pointer kopiert wurde, wird um einen solchen Betrag erhöht, so daß die Adresse nun auf den Beginn des Puffers zeigt, und nicht mehr auf die size-Komponente.

stringfub( name)
Die Operation dieses Makros macht die Aktion des Makros stringbuf() rückgängig.
Anwendung nur nach einer Anwendung von stringbuf() !

stringsize(name)
Repräsentation der Größe des angelegten Arrays in Byte (size).

stringlen( name)
Aktuelle Elementelänge des Inhalts des Arrays (len).

stringoff( name)
Aktueller Elementeoffset des Arrays (off).

stringwid( name)
Aktuelle Elementbreite des Arrays in Byte (wid).

stringshft(name)
Aktuelle Elementschiebebreite des Arrays in Byte (shft).

stringswid(name)
Repräsentation des Byte swid.

stringcntl(name)
Repräsentation des Byte cntl.

stringfilc(name)
Repräsentation des Byte filc.

stringmag1(name)
Repräsentation des Byte mag1.

stringmag2(name)
Repräsentation des Byte mag2.

stringbufsz(name)
Die Größe des Puffers in Byte (buf[]).
Das hier gezeigte flexible Array aus der Struktur hat keine Größe, sondern der per Pointer-Casting unterlegte Teil des angelegten Arrays.

stringlenmax(name)
Die maximal mögliche Elementelänge für len.

Funktionen

Funktionen mit Unterstrich string_xxx() sind (eher) für internen Gebrauch. Die anderen stringxxx() sind typische Anwenderfunktionen.

Alle Funktionen, die ein String-Objekt bearbeiten sollen, prüfen das Objekt auf NULL-Pointer und vorhandene MAGIC-Nummern (MAG1=19, MAG2=236). Die MAGICs liegen auf den Objektadressen 8 und 15. Entweder der Prozeß bricht wegen SIGSEGV ab, oder weil nicht beide MAGICs passen. Es ist kaum vorstellbar, daß beide MAGICs bei einem Objekt passen, das kein initialisiertes String-Objekt ist.

Wenn der Datei-Zeiger einer leeren Datei mittels lseek() auf eine höhere Position bewegt wird und auf diese Position geschrieben wird, wird bis zu dieser Position mit 0 aufgefüllt, oder beim Lesen verhält es sich so, als ob.
Dieses Verhalten wurde fast genau so in die Funktionen stringsetlen() und stringsetoff() implementiert. Diese Funktionen füllen tatsächlich ein entstandenes Loch mit dem Füllzeichen FILC2, sofern die Steuerbits lfil bzw. ofil auf 1 gesetzt sind.
Mit diesen Funktionen können die Puffer gezielt abschnittsweise mit verschiedenen filc gefüllt werden. Dies ist allerdings ein Nebennutzen.

Nach Änderung der Länge len zu einem größeren Wert, befindet sich zwischen dem alten und dem neuen Wert eine Lücke mit (eventuell) uninitialisierten Daten. Dieses Loch wird aufgefüllt. Beim Offset off entsteht ein solches Loch, wenn dieser über die Länge hinaus vergrößert wird. Die Datenlücke befindet sich dann zwischen dem Längenwert len und dem neuen Wert des Offsets.

_Noreturn void string_err(int e, const char *fu)

Diese Fehlerfunktion kehrt nicht zurück, weil an deren Ende die Funktion exit() unbedingt aufgerufen wird, die ebenfalls nicht zurückkehrt. Dies wird dem Compiler durch _Noreturn angezeigt, wodurch der deren Aufrufe nach der letzten oder einzigen ret-Instruktion einsetzt. Dadurch wird Aufwand gespart, wegen der freizügigen Verwendung von Registern, deren Inhalte nicht abgesichert und zurückgeholt werden müssen.
Bei Fehlern muß der Prozeß beendet werden, da der jeweils nachfolgende Code von einwandfreier Operation der vorhergehenden Funktionen ausgehen muß.

void string0t(void *dst)

Der Pufferinhalt eines String-Objekts wird null-terminiert, um stringbuf(dst) an einen Code übergeben zu können, der einen null-terminierten String oder einen null-terminierten Array-Inhalt erwartet. Es werden wid0-Bytes geschrieben.

void stringsetlen(void *dst, CTLTYP len)

Diese Funktion macht den Unterschied zwischen null-terminierten Zeichenketten und den hier vorliegenden Strings deutlich. Die String-Länge (len) kann beliebig oft hintereinander zwischen 0 und Maximum geändert werden, ohne daß der String in seinem Puffer inhaltlich geändert wird. Lesevorgänge berücksichtigen diesen Wert, indem sie entsprechend viel oder wenig oder keine Daten aus dem Puffer lesen.
Siehe auch oben eine Detail-Beschreibung (Loch) zu dieser Funktion.

void stringsetoff(void *dst, CTLTYP off)

Diese Funktion setzt den Offset (off) und verändert die Länge (len) entsprechend. Die Länge wird maximal auf den Wert 0 verringert. Von anderen Funktionen wird ab dem Offset gelesen und geschrieben.
Siehe auch oben eine Detail-Beschreibung (Loch) zu dieser Funktion.

void stringsetwid(void *dst, uchar wid)

Diese Funktion setzt die Elementbreite (wid) des String-Objekts und berechnet die Parameter len, off und shft entsprechend neu. Durch Vergrößerung der Breite entfällt ein zuvor eventuell vorhandener Divisionsrest.

CTLTYP stringset(void *dst, void *str, CTLTYP widval, CTLTYP nval)
Ein String-Objekt kann mit dieser Funktion auf drei Arten gesetzt werden:  Falls str nicht Null ist, ist widval die Elementbreite von str und nval zeigt die Anzahl Elemente an, die ab Offset (dst) kopiert werden sollen. Hat nval seinen maximalen Wert ~(CTLTYP)0, muß str null-terminiert sein.

Falls str Null ist, wird der Wert in widval nach dst kopiert, nval-mal. Die Elementbreite wid des Zieles dst wird berücksichtigt. Es wird derjenige niederwertige Teil von widval, der zur Zielbreite paßt, kopiert. Die Elementbreite der Quelle str darf nicht größer sein, als die Breite des Zieles. Retourniert wird die Anzahl kopierter Elemente.

void stringrev(void *sp)

Die Inhalte der Elemente eines String-Objektes werden in ihrer Reihenfolge umgedreht. Von unten nach oben  wird  von oben nach unten. Ein Offset off, die Länge len und die Breite wid werden berücksichtigt.

void stringmov(void *zq, CTLTYP zp, CTLTYP qp, CTLTYP ne)

Diese Funktion nimmt nur ein String-Objekt zq entgegen und erlaubt Kopieraktionen innerhalb dieses Objektes. Die weiteren Argumente sind die Zielposition zp, die Quellposition qp und die Anzahl Elemente ne, die kopiert werden sollen. Es kann von unten nach oben und von oben nach unten kopiert werden. Auch überlappend. Bei gleichem Zielwert und Quellenwert oder Anzahl 0 wird sofort still abgebrochen, denn es gibt in solch einem Fall nichts zu tun. Vor dem Kopieren berechnet die Funktion viele Fehlersituationen.

0123456789012345678901234567890123456789
0         o=10      l=10      m=30
|---------|---------|---------|  n=5
 ----z    ----z----z----z
----q    ----q----q----q
z----    z----z----z---- z----
 q----    q----q----q---- q----

Vorstehend eine Darstellung als Hilfsmittel für analytische Betrachtungen. Beim Kopieren nach oben wächst der Verlauf nach unten, und umgekehrt. Schreiben und Lesen außerhalb des Objektes sind natürlich verboten. Schreiben unterhalb der Offset-Position ist gesperrt. Schreiben einer Dateninsel hinter die Länge len, also Erzeugung eines Datenlochs, ist gesperrt. Lesen von potentiell uninitialisierten Daten (hinter der Länge) ist gesperrt. Die Länge len wird nach gültigem Schreiben angepaßt, falls sie größer als zuvor ist. Die Positionen müssen ohne Offset off enthaltend angegeben werden, denn dieser wird intern addiert.
Beispiele: Ein Dateninhalt kann auf und hinter die aktuelle Länge geschrieben werden. Bei genügend Platz im Objekt kann also der Inhalt verdoppelt werden:  zp= len+len-1qp= len-1ne= len .  Hier werden die Daten ab Offset berücksichtigt, wobei der Offset initial 0 ist.
Ein mit stringstr() gefundener Substring kann entfernt werden, indem der Inhalt darüber auf den Anfang des Substrings kopiert wird, und anschließend die Länge len entsprechend gekürzt wird.

ssize_t stringstr(const void *buf, const void *str, ssize_t pos[3])

Das Suchmuster in str wird in dem Dateninhalt buf ab Offset off gesucht. Die beiden String-Objekte müssen gleiche Breiten wid haben. In beiden wird der Offset berücksichtigt. Das Array pos[] informiert über das Suchergebnis und nimmt im ersten Element pos[0]= p die Position entgegen. Als Startposition muß 0 gegeben werden. Diese Position wird auch eingesetzt, falls pos ein Null-Pointer ist. Nach Rückkehr der Funktion ist die Fundposition in pos[0] enthalten, oder -1, wenn das Suchmuster nicht gefunden wurde. Die Weitersuchposition ist in pos[1] enthalten: pos[0]= pos[1], oder -1, falls ein Weitersuchen sinnlos ist. Die Länge str:len ist in pos[2] enthalten. Retourniert wird derselbe Wert, der in pos[0] geschrieben wird (falls pos kein Null-Pointer ist). Eine Schleifenbedingung für alle Vorkommnisse kann so:  while (pos[1] > 0) codiert werden.
Testausgaben:

1 5 4   toga....togatog..togatoga...toga...
9 13 4  togatog..togatoga...toga...
18 22 4 togatoga...toga...
22 26 4 toga...toga...
29 -1 4 toga...

1 5 4   toga....togatog..togatoga..toga....
9 13 4  togatog..togatoga..toga....
18 22 4 togatoga..toga....
22 26 4 toga..toga....
28 32 4 toga....
-1 -1 4

Eine Abwahl des Arrays (pos==0) ist selten sinnvoll. Die Funktion arbeitet prinzipiell binär. Somit können beispielsweise beliebige Dateiinhalte gesucht werden. Die Elementbreite wid kann bis zu 8 Byte betragen. Der Offset off ist in den gelieferten Positionswerten enthalten. Daher kann beispielsweise ein Ausdruck sp->buf.u1 + pos[0] verwendet werden. Im Zusammenhang mit dieser Funktion ist es meist sinnvoll, den Typ STRING* zu verwenden.

ssize_t stringcmp(const void *ac, const void *bc)

Diese Vergleichsfunktion vergleicht nicht einfach nur unsigned char, sondern Elemente mit einer Breite wid von 1|2|4|8 Byte. Die Breite muß bei den beiden String-Objekten ac und bc gleich sein. Desweiteren ist die Vorzeichenbehaftung beim Vergleich wählbar. Dazu dient das Steuerbit sign, das ebenfalls bei beiden Objekten einen gleichen Wert haben muß. Bei den Breiten 1|2 wird die Differenz  ac-bc  retourniert. Bei den größeren Breiten die Werte +1 oder -1, oder 0 bei Gleichheit. Ein kürzerer String wird (bei den Breiten 1|2) hinter seinem letzten Element als der Wert 0 angenommen:  0-w | w-0 .

void stringcpy(void *dst, const void *src)

Diese Kopierfunktion sorgt dafür, daß das Ziel (dst) nach ihrer Aktion identisch mit der Quelle (src) ist, mit Ausnahme von size. Das bedeutet, daß der Zieloffset (off) ignoriert wird! Es wird eben alles hinter size kopiert. Kopiert wird mit maximaler Breite AL.
stringcats(ziel, quelle, (void*)0)  kopiert ebenfalls, berücksichtigt aber einen Offset.

CTLTYP stringcats(void *dst, const void *src, ...)

In den Puffer des Ziels dst werden ab Offset off die Inhalte der Quellen src und allen weiteren (...) unter jeweiliger Berücksichtigung von Länge len und Offset off hintereinander kopiert (verkettet). Hinter der letzten Quelle muß das beendende Argument (void*)0 folgen. Die Elementbreiten wid aller übergebenen Objekte dürfen beliebig unterschiedlich sein. Retourniert wird die Anzahl der kopierten Bytes. Diese Anzahl wird abhängig von der Element-Breite (typ-abhängig) dividiert, um mit dem Ergebnis die Länge dst:len zu setzen, wobei ein Divisionsrest gegebenenfalls entfernt wird.
Diese Funktion kopiert kompromißlos schnell. Es werden alle Alignments  64,32,16,8,4,2  gesucht, die jeweils bei Ziel und Quelle in Gleichheit vorliegen. Eine solche Funktion für normale C-Strings (CatS) hat sich in der Praxis seit 1995 außerordentlich gut bewährt.

void stringinfo(const void *src, FILE *fp, const char *info)

Die Werte der Parameter size, len, off, wid des String-Objektes src werden ausgegeben. Falls fp Null ist, benutzt die Funktion stdout, anderenfalls fp. Argument info darf Null sein und bedarf keiner weiteren Erklärung.

ssize_t stringput(const void *src, FILE *fp, const char *info)

Der Pufferinhalt des String-Objektes src wird ab Offset off ausgegeben. Die Werte von wid dürfen 1 und 4 (wchar_t) betragen. Falls fp Null ist, benutzt die Funktion stdout, anderenfalls fp. Argument info darf Null sein und bedarf keiner weiteren Erklärung. Es wird die Anzahl ausgegebener Zeichen retourniert. Bei Fehler der Ausgabefunktionen wird -1 retourniert.



Copyright © 2021 - Helmut Schellong

programmiersprache C string klasse