POSIX: Arbeiten mit Wide Charactersvon Steve Graegert

January 21st, 2006 Permalink

Viele Zeichensätze erfordern den Einsatz von "breiten Zeichen" (wide characters), um die für das jeweilige Zeichen notwendigen Informationen zu speichern, da der Zeichensatz durchaus aus mehr als 256 Zeichen bestehen kann. Wide Character sind zu groß (zu "breit") für den char Datentyp. Daher wurde der wchar_t-Datentyp zur Speicherung solcher Zeichen eingeführt.

Eine Zeichenkette, der ein L vorangestellt wurde, ist immer eine Wide Character Constant. Intern wird zur Ablage von WC-Konstanten ein Integer-Typ verwendet, der entweder in oder definiert ist. Ebenso wie normale Zeichen mit oktalen oder hexdezimalen Escape-Sequenzen versehen werden können, funktioniert das auch mit WC-Konstanten, solange ein L vorangestellt wird.

Die Definition von Wide Character Constants unterscheidet sich nicht von der schmaler Zeichen:

wchar_t wc = L'Z';
wchar_t wmc = L'XYZ';
wchar_t *wstring = L"Hello World!";
wchar_t *x = L"Hello World";
wchar_t z[] = L"Hello World";

Im Gegensatz zur NUL-Terminierung schmaler Zeichenketten ist die Terminierung hier 32 Bit lang.

Zwar lassen sich WC-Konstanten ebenso einfach deklarieren, wie ihre schmalen Pendants, allerdings müssen wir bei der Arbeit mit breiten Zeichen auf Besonderheiten einstellen.

Nicht mallocieren

Viele Programmierer gehen bei der Arbeit mit Wide Characters vor, wie Sie es mit schmalen Zeichen gewohnt sind. Folgender Code ist in der schmalen Zeichenbreite durchaus üblich:

char* wc = (char *)malloc(4);
strcpy(wc, "abc");

Übertragen auf die breite Zeichenwelt ergeben die beiden obigen Ausdrücke nur wenig Sinn:

wchar_t* wc = (wchar_t *)malloc(4);
wcscpy(wc, "abc");

Während der erste Ausdrück zwar syntaktisch richtig ist, wird nur Speicherplatz für 1 breites Zeichen reserviert (da wchar_t als unsigned int repräsentiert wird), weil malloc nur n Bytes reserviert, in diesem Fall also 4. Desweiteren beschwehrt sich der Compiler über den Versuch eine schmale Zeichenkonstante in einen breiten Datentyp zu kopieren. Besser wäre wcscpy(wc, L"abc")

Die libc-Bibliothek sieht für die Konvertierung von schmalen Zeichenkonstanten in ihr breites Pendant die Funktion mbstowcs vor:

wchar_t* wc = (wchar_t *)malloc(8 * (sizeof(wchar_t)));
mbstowcs(wc, "abc", 4);

Breite Zeichen lesen und schreiben

Um breite Zeichen von einem Stream zu lesen, bietet sich die Bibliotheksfunktion fgetwc(3) an, die genauso verwendet wird, wir wir es von fgetwc(3) kennen:

#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
 
int main(int argc, char **argv) {
    wint_t  retval;
    FILE    *fp;
    wchar_t *pwcs;
 
    setlocale(LC_ALL, "");
 
    if ((fp = fopen("file", "r")) == NULL) {
        /* Error handling */
    } else {
        /* pwcs points to a wide character buffer of BUFSIZ. */
        while ((retval = fgetwc(fp)) != WEOF){
            *pwcs++ = (wchar_t)retval;
            /* break when buffer is full */
        }
    }
    /*  Process the wide characters in the buffer  */
    return (0);
}

Das gleiche läßt sich auch über getwchar(3) sagen:

#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
 
int main(int argc, char **argv) {
    wint_t  retval;
    FILE    *fp;
    wchar_t *pwcs;
 
    setlocale(LC_ALL, "");
 
    while((retval = getwchar()) != WEOF){
        /* pwcs points to a wide character buffer of BUFSIZ. */
        *pwcs++ = (wchar_t)retval;
        /* break on buffer full */
    }
    /* Process the wide characters in the buffer */
    return (0);
}

Zum zeilenweisen Einlesen von Dateien verwenden wir fgetws(3):

#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
int main(int argc, char **argv) {
    FILE    *fp;
    wchar_t *pwcs;
 
    setlocale(LC_ALL, "");
 
    /* Error Handling if fopen was not successful. */
    if((fp = fopen("file", "r")) == NULL) {
        /*  Error handling  */
    } else {
        /* pwcs points to wide character buffer of BUFSIZ.  */
        while(fgetws(pwcs, BUFSIZ, fp) != (wchar_t *)NULL){
           /*
            * pwcs contains wide characters with null
            * termination.
            */
        }
    }
}

Schließlich sehen wir uns noch an, wie fputwc(3) und fputws(3) arbeiten:

#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
 
int main(int argc, char **argv) {
    int     index, len;
    wint_t  retval;
    FILE    *fp;
    wchar_t *pwcs;
 
    setlocale(LC_ALL, "");
 
    /* Error Handling if fopen was not successful. */
    if((fp = fopen("file", "w")) == NULL){
        /* Error handling */
    } else {
       /*
        * Let len indicate number of wide chars to output.
        * pwcs points to a wide character buffer of BUFSIZ.
        */
        for (index = 0; index &lt; len; index++){
            if ((retval = fputwc(*pwcs++, fp)) == WEOF)
            /* write error occurred */
            break; /* errno is set to indicate the error. */
        }
    }
}
#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
 
int main(int argc, char **argv) {
	int     retval;
	FILE    *fp;
	wchar_t *pwcs;
 
	setlocale(LC_ALL, "");
 
	/* Error Handling if fopen was not successful. */
	if((fp = fopen("file", "w")) == NULL){
		/*  Error handler  */
	} else {
		if ((retval = fputws(pwcs, fp)) == -1) {
			/* Write error occurred                */
			/*  errno is set to indicate the error  */
		}
	}
}

Manipulation breiter Zeichen

Folgende Bibliotheksfunktionen sind für die Verarbeitung von Wide Character Strings vorgesehen:

  • wcrtomb() – Konvertiert eine WC-Konstante in ein Zeichen (wcrtomb.c)
  • wcscat() – Verbindet zwei WC-Konstanten(wcscat.c)
  • wcschr() – Lokalisiert ein Zeichen in einer WC-Konstante(wcschr.c)
  • wcscmp() – Vergleicht zwei WC-Konstanten(wcscmp.c)
  • wcscoll() – Vergleicht zwei WC-Konstanten unter Berücksichtigung der Werte in LC_COLLATE (wcscoll.c)
  • wcscpy() – Kopiert eine WC-Konstante in einen breiten Speicherbereich (wcscpy.c)
  • wcscspn() – Bestimmt die Länge eines komplementären Substrings (wcscspn.c)
  • wcsftime() – Konvertiert Datum und Zeit in eine breite Zeichenkonstante
  • wcslen() – Bestimmt die Länge einer WC-Konstante
  • wcsncat() – Verbindet einen Teil einer WC-Konstante mit einer anderen
  • wcsncmp() – Vergleicht einen Teil einer WC-Konstante mit einer anderen
  • wcsncpy() – Kopiert einen Teil einer WC-Konstante in einen breiten Speicherbereich
  • wcspbrk() – Lokalisiert eine Zeichenkette in einer WC-Konstante (wcspbrk.c)
  • wcsrchr() – Lokalisiert die letzte Position eines Zeichens in einer WC-Konstante (wcsrchr.c)
  • wcsrtombs() – Konvertiert eine WC-Konstante in ihr schmales Pendant
  • wcsspn() – Gibt die Länge eines Substrings in einer WC-Konstante aus (wcsspn.c)
  • wcsstr() – Lokalisiert eine Zeichenkette in einer WC-Konstante (exkl. NUL-Terminierung) (wcsstr.c)
  • wcstod() – Konvertiert eine WC-Konstante in einen Wert mit doppelter Präzision (wcstod.c)
  • wcstof() – Konvertiert eine WC-Konstante in einen Wert mit doppelter Präzision
  • wcstoimax() – Konvertiert eine WC-Konstante in einen Integerwert
  • wcstok() – Teilt eine WC-Konstante in Einzelteile (wcstok.c)
  • wcstol() – Konvertiert eine WC-Konstante in einen long int (wcstol.c)
  • wcstold() – Konvertiert eine WC-Konstante in einen Wert mit doppelter Präzision
  • wcstoll() – Konvertiert eine WC-Konstante in einen long int
  • wcstombs() – Konvertiert eine WC-Konstante in eine Zeichenkonstante (wcstombs.c)
  • wcstoul() – Konvertiert eine WC-Konstante in einen unsigned long (wcstoul.c)
  • wcstoull() – Konvertiert eine WC-Konstante in einen unsigned long
  • wcstoumax() – Konvertiert eine WC-Konstante in einen Integer
  • wcswcs() – Findet eine WC-Konstante (obsolet) (wcswcs.c)
  • wcswidth() – Anzahl der Spaltenpositionen einer WC-Konstante (wcswidth.c)
  • wcsxfrm() – Transformiert eine WC-Konstante (wcsxfrm.c)
  • wctob() – Konvertiert eine WC-Konstante in ein Einzelbytezeichen
  • wctomb() – Konvertiert eine WC-Konstante in eine schmale Zeichenkette (wctomb.c)
  • wctrans() – Definiert das Mapping von Zeichen
  • wctype() – Definiert eine Zeichenklasse
  • wcwidth() – Anzahl der Spaltenpositionen eines WC-Codes (wcwidth.c)

Kommentieren