Ich habe gerade erst angefangen, mich mit cpp zu beschᅵftigen. Bisher
programmierte ich nur in C. In folgendem Testprogramm will ich durch den
scope-Operator auf die gewᅵnschte print-Funktion zugreifen. Einmal habe
ich sie in der Stammklasse und dann in der abgeleiteten Klasse. So wie
ich das verstanden habe, dient der scope dazu, auf ᅵbergeordnete
Elemente zuzugreifen. Ich bekomme aber nur die Meldung, das links neben
dem scope (unten die Zeile "version::print()") eine Klasse stehen muss.
"version" habe ich doch als Klasse angelegt !
Die Castings habe ich gesetzt, um alle unnᅵtigen Compilermeldungen im
Vorfeld zu vermeiden.
Bis zur problemat. Zeile tut das Programm, was es soll. Beim
problematischen Teil will ich die print-Funktion aus der Stammklasse
aufrufen; aber nicht direkt sondern ᅵber die abgeleitete Klasse.
Statt des scopes habe ich diverse andere Schreibweisen versucht. Brachte
alles nichts. Mache ich hier vielleicht einen grundsᅵtzlichen Denkfehler?
Namensgebungen und weiterer Sinn des Programms sind hier vᅵllig
unwichtig ;-)
--- cut ---
#include "stdafx.h"
#include <iostream>
class printInfo {
public: (void)print(void) {printf("Das ist das Testprogramm 1\n");}
(void)printValText(int x) {printf("Wert : %d\n",x);}
};
class printVersion : public printInfo {
public : (void)print(int version) {printf("Version: %d\n",version);}
};
int _tmain(int argc, _TCHAR* argv[])
{
printInfo info;
class printVersion version;
info.print();
info.printValText(123);
version.print(42);
//Und nun eine alternative Ausgabe:
info.print();
version::print(); //Fehler ! Erkennt "version" nicht als Klasse an !!
return 0;
}
--- cut ---
--
Gruss
Dirk
[...]
Mehrere Probleme. (Nicht erstaundlich, wenn du erst mit C++
anfängst.)
> --- cut ---
> #include "stdafx.h"
Du weißt, hoffentlich, dass dieses Include rein Windows ist (und
dass du es in diesem Programm nicht brauchst).
> #include <iostream>
> class printInfo {
> public: (void)print(void) {printf("Das ist das Testprogramm 1\n");}
Mehrere Sachen, die obwohl legal ehre ungewöhnlich sind:
-- Warum die Klammern um das ersten void? Obwohl erlaubt, sind
sie äußerst ungewöhnlich, sowohl in C als auch in C++. Ich
habe sie nie anderswo gesehen. Und bei komplizierteren
Rückgabetypen (Zeigern auf Funktionen oder Tabellen) werden
sie nicht erlaubt.
-- Das zweite void ist in C++ nicht nötig, und fällt in den
meisten C++ Stylen weg. (Häufig wird es als "C'ism"
betrachtet, mehr oder weniger als ein Hinweis, dass der
Programmierer C++ nicht richtig kennt.)
-- Du hast <iostream> includiert, benutzt aber printf. In
Allgemein sollst du printf vermeiden; benutze lieber
std::cout. Aber wenn auf irgendeinem Grund du printf
benutzt (z.B. weil andere Teile des Programms in C sind),
dann sollst du <stdio.h> includieren, genau wie in C.
(Mit std::cout wäre die Zeile:
std::cout << "Das ist das Testprogram 1" << std::endl ;
.)
> (void)printValText(int x) {printf("Wert : %d\n",x);}
> };
> class printVersion : public printInfo {
>
> public : (void)print(int version) {printf("Version: %d\n",version);}
> };
> int _tmain(int argc, _TCHAR* argv[])
Wieder Windows'isme. Sowohl in C als in C++ muss die
Hauptfunktion »main« heißen. Die ein char** als zweite Parameter
nimmt.
> {
> printInfo info;
> class printVersion version;
Das Schlüsselwort »class« wird hier nicht gebraucht. Du sollst
die zweite Variable genau wie die erste definieren:
printVersion version ;
Die Benutzung von »class« hier ist nur auf
C-Kompatibilitätsgrunden erlaubt. (In C hättest du:
struct printVersion version ;
schreiben müssen.)
> info.print();
> info.printValText(123);
> version.print(42);
> //Und nun eine alternative Ausgabe:
> info.print();
> version::print(); //Fehler ! Erkennt "version" nicht als Klasse an !!
Weil version keine Klasse ist, sondern eine Variable. Die Klasse
heißt printVersion.
Mir ist es nicht ganz klar, was du versuchst, hier zu tun.
Welche Funktion willst du aufrufen, auf welchem Objekt. Um die
Funktion printInfo::print() auf dem Objekt version aufzurufen,
musst du beides angeben:
version.printInfo::print() ;
(In der Praxis aber sollst du das fast nie tun.)
> return 0;
> }
> --- cut ---
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Also ich habs mal hübscher und cplusplusiger gemacht:
std::cout statt prinf, main statt _tmain usw.
Überflüssige voids und Klammern entfernt.
#include <iostream>
class printInfo {
public:
void print() { std::cout << "Das ist das Testprogramm 1" <<
std::endl; }
void printValText(int x) { std::cout << "Wert : " << x <<
std::endl; }
};
class printVersion : public printInfo {
public:
void print(int version) {std::cout << "Version: " << version <<
std::endl; }
};
int main(int argc, char** argv)
{
printInfo info;
printVersion version;
info.print();
info.printValText(123);
version.print(42);
//Und nun eine alternative Ausgabe:
info.print();
version::print(); //Fehler ! Erkennt "version" nicht als Klasse
an !!
return 0;
}
Nun zum eigentlichen. Da gibt es einige Punkte:
1. Der Scope operator agiert auf der Sichtbarkeit.
Wäre print() in printVersion statisch
class printVersion : public printInfo {
public:
static void print(int version) {std::cout << "Version: " <<
version << std::endl; }
};
Dann könnstest du print so aufrufen:
printVersion::print(42);
Zu beachten: printVersion ist die Klasse, version ist eine Instance,
also ein konkretes
Exemplar der Klasse. Und natürlich mit 42 als int-Argument. Denn print
(int version)
verlangt ja ein int-Argument. Btw. ist es üblich Klassennamen groß zu
Schreiben und
Intances klein.
Eine statische Funktion ist grob gesagt wie eine globale Funktion aber
mit
spezieller Sichtbarkeit. Statische Funktionen werden über die Klasse
aufgerufen,
nicht-statische über ein konkretes Exemplar (engl. instance) dieser
Klasse.
2. wieder nicht static
class printVersion : public printInfo {
public:
void print(int version) {std::cout << "Version: " << version <<
std::endl; }
};
Hier ist print nicht statisch und muss über das Object/dem Exemplar
aufgerufen
werden. Und dazu nimmt man nicht den Scope, sondern den Punkt-
Operator.
version::print(42); //funktioniert
Zu beachten: wieder mit int-Argument.
3. version.print();
Zwar erbt die Klasse printVersion von printInfo eine Methode print().
Diese ist aber nicht sichtbar! Und zwar deshalb weil printVersion
auch wieder eine Funktion mit Namen print deklariert. Und dabei ist
unerheblich welche Argumente diese Methode hat! Im Gegensatz
zu Java nebenbei.
Das originale print aus der Basisklasse printInfo wird verdeckt.
Möchtest du es explizit aufrufen, dann hilft hier der scope operator
version.printInfo::print();
Du ruftst am konkreten Exemplar version der Klasse printVersion
die Memberfunktion/Methode print() die von der Basisklasse
printInfo geerbt wird.
4. hast du zwar nicht gefragt, liegt aber nahe...
Möchtest du in printVersion die Funktion print() *überschreiben*,
d.h. ihr ein andere Verhalten geben, dann musst du sie virtuell
deklarieren.
//falsch
class A{
public:
void print() { std::cout << "ich bin ein A" << std::endl; }
};
class B : public A{
public:
void print() { std::cout << "ich bin ein B" << std::endl; }
};
A a;
B b;
A* ap = &b;
a.print(); //druckt "ich bin ein A"
b.print(); //druckt "ich bin ein B"
ap->print(); //druckt "ich bin ein A"!!!
ap zeigt zwar in wirklichkeit auf ein B-Objekt. Das "weiss" der
Compiler
aber nicht. Der statische Typ ist A und deshalb wird A::print()
aufgerufen.
B::print() überdeckt wieder wie oben A::print().
//richtig
class A{
public:
virtual void print() { std::cout << "ich bin ein A" <<
std::endl; }
};
class B : public A{
public:
virtual void print() { std::cout << "ich bin ein B" <<
std::endl; }
};
A a;
B b;
A* ap = &b;
a.print(); //druckt "ich bin ein A"
b.print(); //druckt "ich bin ein B"
ap->print(); //druckt "ich bin ein B", da ap auf ein B-Objekt zeigt.
Bei virtuellen Funktion wird der dynamische Typ zur Laufzeit
ausgewertet.
Es wird also B:print() aufgerufen, weil der dynamische Typ halt B ist.
5. Jetzt wirds ganz "verrrückt":
class A{
public:
virtual void print() { std::cout << "ich bin ein A" <<
std::endl; }
};
class B : public A{
public:
virtual void print(int i) { std::cout << "ich bin ein B " << x <<
std::endl; }
};
Die Methode print in B hat jetzt eine andere Signatur, sie hat ein int-
Argument.
Damit *überschreibt* print(int i) die geebte argumentlose Methode
print von A
*nicht*. Sondern - wie oben - print(int i) verdeckt wieder diese print
() Methode.
Obwohl B die Methode print() erbt ist sie wieder nicht sichtbar.
Das virtuel bei print(int i) ändert daran nichts. Das wird erst wieder
interessant
wenn B weiter abgeleitet wird.
Das Verhalten ist nicht sehr intuitiv und in Java auch anders.
Jedenfalls eine
beliebte Fehlerquelle.
dl schrieb:
> Hallo
>
> Ich habe gerade erst angefangen, mich mit cpp zu beschäftigen. Bisher
> programmierte ich nur in C. In folgendem Testprogramm will ich durch
> den scope-Operator auf die gewünschte print-Funktion zugreifen.
> Einmal habe ich sie in der Stammklasse und dann in der abgeleiteten
> Klasse. So wie ich das verstanden habe, dient der scope dazu, auf
> übergeordnete Elemente zuzugreifen. Ich bekomme aber nur die Meldung,
> das links neben dem scope (unten die Zeile "version::print()") eine
> Klasse stehen muss. "version" habe ich doch als Klasse angelegt !
>
> Die Castings habe ich gesetzt, um alle unnötigen Compilermeldungen im
> Vorfeld zu vermeiden.
Warum klammerst du die Rückgabetypen der Methoden/Funktionen?
>
> Bis zur problemat. Zeile tut das Programm, was es soll. Beim
> problematischen Teil will ich die print-Funktion aus der Stammklasse
> aufrufen; aber nicht direkt sondern über die abgeleitete Klasse.
> Statt des scopes habe ich diverse andere Schreibweisen versucht.
> Brachte alles nichts. Mache ich hier vielleicht einen grundsätzlichen
> Denkfehler?
Deine alternative Ausgabe verstehe ich so,
dass du gerne eine Methode ausführen möchtest, ohne dass
du eine Instanz der Klassen erstellen möchtest.
Das geht. Dazu müssen entsprechende Methoden static sein.
Dann funktioniert auch der Aufruf
Klassenname::Methodenname(<Werte für erforderliche Parameter>);
Deinen Code habe ich zum direkten Vergleich noch mal
unverändert hier angegeben. Darunter befindet sich
ein modifizierter Code, der das tuen sollte, was du möchtest.
Gruß Robert
[Dein Code]
>
> --- cut ---
>
> #include "stdafx.h" #include <iostream>
>
> class printInfo {
>
> public: (void)print(void) {printf("Das ist das Testprogramm 1\n");}
> (void)printValText(int x) {printf("Wert : %d\n",x);} };
>
>
> class printVersion : public printInfo {
>
> public : (void)print(int version) {printf("Version: %d\n",version);}
>
> };
>
>
> int _tmain(int argc, _TCHAR* argv[]) { printInfo info; class
> printVersion version;
>
> info.print(); info.printValText(123);
>
> version.print(42);
>
> //Und nun eine alternative Ausgabe: info.print(); version::print();
> //Fehler ! Erkennt "version" nicht als Klasse an !!
>
> return 0; }
>
> --- cut ---
Probier mal das:
/*Beginn der main.cpp */
#include<iostream>
class printInfo {
public:
void static print(void) {
printf("Das ist das Testprogramm 1\n");
}
void printValText(int x) {
printf("Wert : %d\n", x);
}
};
class printVersion: public printInfo {
public:
void static print(int version) {
printf("Version: %d\n", version);
}
};
int main(int argc, char* argv[]) {
std::cout<<"Erstelle Instanzen der Klassen printInfo und printVersion\n";
printInfo info;
printVersion version;
std::cout<<"Methodenaufruf der Instanz info der Klasse printInfo\n";
info.print();
info.printValText(123);
std::cout<<"Methodenaufruf der Instanz version der Klasse printVersion\n";
version.print(42);
version.printValText(2*42);
//Und nun eine alternative Ausgabe:
std::cout<<"Aufruf als statischen Klassen-Methoden\n";
printInfo::print();
printVersion::print(2);
return 0;
}
/*Ende der main.cpp */
D.h., es gibt keine standardgem��e M�glichkeit, Unicode-Parameter an ein
Programm zu �bergeben? (wchar_t** argv ?)
Dann ist der Standard wohl nicht mehr ganz zeitgem��.
Markus
Die Strategie ist nicht wirklich schlau. Compilerwarnungen sollte man
*immer* ernst nehmen und nur dann unterdrᅵcken, wenn man absolut sicher
ist, dass der *Compiler* hier irrt.
> Bis zur problemat. Zeile tut das Programm, was es soll. Beim
> problematischen Teil will ich die print-Funktion aus der Stammklasse
> aufrufen; aber nicht direkt sondern ᅵber die abgeleitete Klasse.
> Statt des scopes habe ich diverse andere Schreibweisen versucht. Brachte
> alles nichts. Mache ich hier vielleicht einen grundsᅵtzlichen Denkfehler?
>
>
>
> Namensgebungen und weiterer Sinn des Programms sind hier vᅵllig
> unwichtig ;-)
>
>
> --- cut ---
>
> #include "stdafx.h"
> #include <iostream>
>
> class printInfo {
>
> public: (void)print(void) {printf("Das ist das Testprogramm 1\n");}
Warum steht hier (void)print? Macht man doch in C auch nicht bzw. das
ist in C++ identisch zu C.
> (void)printValText(int x) {printf("Wert : %d\n",x);}
>
> };
>
>
> class printVersion : public printInfo {
>
> public : (void)print(int version) {printf("Version: %d\n",version);}
zusᅵtzlich:
using printInfo::print;
>
> };
>
>
> int _tmain(int argc, _TCHAR* argv[])
> {
> printInfo info;
> class printVersion version;
class ist hier unnᅵtig (falsch??), auch fᅵr struct braucht man kein
typedef oder struct XY bei der Verwendung.
>
> info.print();
> info.printValText(123);
>
> version.print(42);
>
> //Und nun eine alternative Ausgabe:
> info.print();
> version::print(); //Fehler ! Erkennt "version" nicht als Klasse an !!
Und dann einfach:
version.print();
>
> return 0;
> }
>
> --- cut ---
>
>
>
Du solltest dir dringend ein gutes C++-Buch zulegen, wenn du C++
wirklich lernen willst. Was du da machst scheint mehr wurschtelei zu
sein, damit wirst du nicht glᅵcklich!
Lars
Der 'char*' zeigt auf eine NTMBS ("null-terminated multi-byte character
sequence"). Der vorgesehene Weg, Unicode ins Programm zu bekommen, ist
dann also wohl schlicht und ergreifend UTF-8.
Stefan
Nein, der aktuelle ist von 1998.
Lars
> >> int _tmain(int argc, _TCHAR* argv[])
> > Wieder Windows'isme. Sowohl in C als in C++ muss die
> > Hauptfunktion »main« heißen. Die ein char** als zweite
> > Parameter nimmt.
> D.h., es gibt keine standardgemäße Möglichkeit,
> Unicode-Parameter an ein Programm zu übergeben? (wchar_t**
> argv ?)
wchar_t** nicht. Die meisten Betriebssysteme unterstützen es
nicht. char** mit UTF-8 funktionniert auf all Unix, die ich
kenne; ich glaube, dass es auch unter Windows geht. (Absolut
portabel kann es nicht sein. Es gibt Systeme, wo Zeichen in
EBCDIC kodiert sind, z.B.)
> Dann ist der Standard wohl nicht mehr ganz zeitgemäß.
Wieso. UTF-8 wird zu eine universele Norm, und geht, wo das
System es unterstützt. (In Allgemein: wchar_t soll man nur
intern benutzen. Sofort Daten das Programm verlassen, gilt char.
Das in einem modernen System UTF-8 enthalten kann und soll.)
Stefan Reuther schrieb:
[...]
> Der vorgesehene Weg, Unicode ins Programm zu bekommen, ist
> dann also wohl schlicht und ergreifend UTF-8.
Magst du evtl ein kleines Beispiel dafür geben?
Gruß Robert
Ich weiß, dass das so ist. Aber das ändert nichts daran, dass es unschön
ist, mehrere Bytes für ein Zeichen zu verwenden. Es geht nämlich zum
Beispiel nicht: if(argv[1][0] == L'א'), was aber sehr praktisch wäre.
Markus
> UTF-8 wird zu eine universele Norm
Warum.
UTF-8 ist Krampf.
Dort nervig wo es eigl. nicht gebraucht wird, und hat dort keine
Vorteile wo es gebraucht wird.
Was spricht gegen UTF-32 mit 1 Zeichen == 1 32bit-int?
Aber das 'meistverbreitetste' Betriebssystem untert�tzt es. Mit dem
aktuellen MSVC ist es �berhaupt kein Problem, UTF-16 Parameter an ein
Programm zu �bergeben:
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow);
wobei 'LPTSTR' nach:
typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
typedef __nullterminated WCHAR *NWPSTR, *LPWSTR, *PWSTR;
typedef LPWSTR PTSTR, LPTSTR;
aufgel�st wird.
Nur ist das nat�rlich nicht standardkonform.
>
>> Dann ist der Standard wohl nicht mehr ganz zeitgem��.
>
> Wieso. UTF-8 wird zu eine universele Norm, und geht, wo das
> System es unterst�tzt. (In Allgemein: wchar_t soll man nur
> intern benutzen. Sofort Daten das Programm verlassen, gilt char.
> Das in einem modernen System UTF-8 enthalten kann und soll.)
UTF-16 und UTF-32 sind auch universelle Normen. Ein Unicodezeichen passt
nunmal nicht in ein Byte. Deshalb sind Typen mit mindestens 2 Byte eben
besser geeignet.
Markus
Wie man die Zeichen reinbekommt? Man ruft das Programm halt passend auf.
Und zum Auswerten eine wchar_t-Sequenz drausmachen kann man dann,
passendes locale vorausgesetzt, mit 'mbstowcs'. Was es da an vorbe-
reiteten Mechanismen gibt, h�ngt halt von der Umgebung ab. Windows
scheint die Zeichen einfach 1:1 durchzureichen; unter Unix mit
UTF8-locale w�rde ich davon ausgehen, das UTF8 zerlegt zu bekommen.
Letztlich reiche ich 99% der so erhaltenen Strings sowieso direkt an
Betriebssystem- bzw. Standardbibliotheksaufrufe durch, die wissen dann
schon damit umzugehen.
Stefan
Die Tatsache, dass UTF-8 immer weniger Speicher braucht als UTF-32.
Keine Endian-Probleme. Abw�rtskompatibel zu ASCII, und damit zu
praktisch allen existierenden APIs (inkl. der C- und C++-Standard-
bibliotheken). Man muss nicht alle APIs neu erfinden, so wie das das
"meistverbreitetste Betriebssystem" tut, und selbst die haben mit UTF-16
keine "ein Zeichen, ein Arrayelement"-Darstellung, und krebsen in den
Standardschnittstellen noch mit DOS-Codeseiten rum.
Zumindest die Anwendungssoftware, die ich so schreibe, macht mit Strings
nur die �blichen Operationen: Aneinanderh�ngen. Auf Gleichheit pr�fen.
Aufspalten an ASCII-Trennzeichen wie ',', '/', ' ' oder '\n'. Vergleich
mit ASCII-Literalen. Alles Dinge die in UTF-8 genauso funktionieren.
Klar, ein paar Operationen werden etwas aufw�ndiger ("richtiger"
lexikalischer Vergleich, Rendering). Und wenn ich ein Textverarbeitungs-
programm schreiben w�rde, dass mit allen Schikanen klarkommen soll
(decomposed unicode, right-to-left und left-to-right gemischt, usw.),
w�rde ich sicher nicht UTF-8 als interne Darstellung w�hlen, aber als
externes Speicherformat ist es doch prima geeignet.
Stefan
> > wchar_t** nicht. Die meisten Betriebssysteme unterstützen
> > es nicht. char** mit UTF-8 funktionniert auf all Unix, die
> > ich kenne; ich glaube, dass es auch unter Windows geht.
> > (Absolut portabel kann es nicht sein. Es gibt Systeme, wo
> > Zeichen in EBCDIC kodiert sind, z.B.)
> Aber das 'meistverbreitetste' Betriebssystem untertützt es.
Nur teilweise. Es gibt wohl eine CreateProcessW, neben
CreateProcess, aber woher komment die wchar_t? ReadFile liest
nur Bytes, soweit ich aus der Dokumentation feststellen kann,
alle Text-orientierten Protokollen auf dem Netz benutzen Bytes,
und verteilen Dateien können auch nur Bytes ermitteln. Solange
der Prozeßor mit keinem anderen Rechner verbunden ist, kann er
benutzen, was er will; sofort eine Verbindung mit anderen
Rechnern besteht, muss er sich anpassen. Und die Welt ist 8-Bit
orientiert. (Ob das eine gute Sache ist, oder nicht, kann man
darüber diskutieren. Es wird sich aber nicht ändern.)
> Mit dem aktuellen MSVC ist es überhaupt kein Problem, UTF-16
> Parameter an ein Programm zu übergeben:
> int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
> LPTSTR lpCmdLine, int nCmdShow);
> wobei 'LPTSTR' nach:
> typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
> typedef __nullterminated WCHAR *NWPSTR, *LPWSTR, *PWSTR;
> typedef LPWSTR PTSTR, LPTSTR;
> aufgelöst wird.
> Nur ist das natürlich nicht standardkonform.
Und auch nicht unbedingt besonders nützlich. Um einen Prozeß
UTF-16 Daten zu geben (mittels CreateProcessW), muss ich die
auch haben.
> >> Dann ist der Standard wohl nicht mehr ganz zeitgemäß.
> > Wieso. UTF-8 wird zu eine universele Norm, und geht, wo das
> > System es unterstützt. (In Allgemein: wchar_t soll man nur
> > intern benutzen. Sofort Daten das Programm verlassen, gilt
> > char. Das in einem modernen System UTF-8 enthalten kann und
> > soll.)
> UTF-16 und UTF-32 sind auch universelle Normen.
So universell sind sie nicht. Die werden kaum im Internet
benutzt, zum Beispiel.
> Ein Unicodezeichen passt nunmal nicht in ein Byte. Deshalb
> sind Typen mit mindestens 2 Byte eben besser geeignet.
Ein Unicodezeichen passt auch nicht in 2 Bytes. Rein formell
soll man UTF-32 überall benutzen. In der Praxis aber sind
Kompromisse oft bessere Lösungen. Wenn ich ein Programm wie ein
Editor schreiben würde, wo ich hin und her in beliebigen Text
walzen müssen, würde ich wahrschein UTF-32 intern benutzen, wenn
ich alle Schriftarten unterstützen müsste, und UTF-16 wenn ich
z.B. mich auf europäischen Sprachen beschränken dürften. Mit
Umwandlung zu und von UTF-8 beim Lesen und Schreiben, aber, weil
die ganze Welt wird sich nicht meinetwegen ümstellen. Da meine
Programme in der Tat aber alle Text rein sequenziell lesen und
bearbeiten, geht auch UTF-8 ohne weiteres intern.
> > UTF-8 wird zu eine universele Norm
> Warum.
Wahrscheinlich weil es eigentlich keine Alternativen gibt.
Unicode ist in zwischen Pflicht. Und die Welt ist 8-Bit
orientiert.
> UTF-8 ist Krampf.
> Dort nervig wo es eigl. nicht gebraucht wird, und hat dort keine
> Vorteile wo es gebraucht wird.
> Was spricht gegen UTF-32 mit 1 Zeichen == 1 32bit-int?
Die Tatsache, dass die ganze Welt 8-Bit orientiert ist, und dass
ein Versuch, dass zu ändern, ist vollig unrealistisch. Je nach
dem, was du im Programm tust, ist es sinnvoll, UTF-32 bzw.
UTF-16 intern im Programm zu verwenden (obwohl für die meisten
Sachen, die ich mache, funktionniert UTF-8 genau so gut, wenn
nicht besser), aber sofort mit der Außenwelt kommuniziert wird,
geht's nur UTF-8.
Es passt auch nicht in 2 Byte.
Lars
> Wahrscheinlich weil es eigentlich keine Alternativen gibt.
wchar, und UTF32 w�ren �lternativen.
Eine Form von UTF8 als Form einer Transportcodierung wo es auf wenige
Speicher ankommt ist ja ok.
Ich denke vorallem an Java. Dort ist zwar oberfl�chlich UTF-8 sowas wie
ein Standard. Aber Java selber kann kein UTF-8.
> Die Tatsache, dass die ganze Welt 8-Bit orientiert ist, und dass
> ein Versuch, dass zu �ndern, ist vollig unrealistisch.
32 ist ein Vielfaches von 8. Und mein Prozessor und auch mein
C++-Compiler sind 32 bit orientiert. Die Tendenz geht zu mehr.
Die menschliche Schrift sollte wichtig genug sein um gleicht richtig
kodiert zu werden. F�r numerische Operationen nimmt man ja auch ints wo
chars locker gereicht h�tten.
> dem, was du im Programm tust, ist es sinnvoll, UTF-32 bzw.
> UTF-16 intern im Programm zu verwenden (obwohl f�r die meisten
> Sachen, die ich mache, funktionniert UTF-8 genau so gut, wenn
> nicht besser), aber sofort mit der Au�enwelt kommuniziert wird,
> geht's nur UTF-8.
Ein gro�es Problem von UTF-8 ist auch, dass es zuviel kann.
Es kann Alt-Ph�nizisch etc. und damit bringts du einige Programme
durcheinander.
Es kann zuviel. Und damit muss ein m�glicher Zeichensatz immer extra
eingeschr�nkt werden. Bei "ISO 8859-1" weiss ich *genau* was ich
bekomme, da die M�glichkeiten die ich geg. Abpr�fen muss uberschaubar sind.
> > Wahrscheinlich weil es eigentlich keine Alternativen gibt.
> wchar, und UTF32 wären Älternativen.
Der Internet ist 8-Bit orientiert. Die meisten Filesysteme auch.
Um überall benutzbar zu sein, muss auch eine Codierung 8-Bit
orientiert sein.
> Eine Form von UTF8 als Form einer Transportcodierung wo es auf
> wenige Speicher ankommt ist ja ok.
Es hat nichts mit dem Speicher zu tun. (Mindestens in den
meisten Fällen.) Heutzutag sind fast alle Rechner,
Übertragungsprotokolle, u.s.w. auf 8 Bits basiert.
> Ich denke vorallem an Java. Dort ist zwar oberflächlich UTF-8
> sowas wie ein Standard. Aber Java selber kann kein UTF-8.
Doch. Amsonsten könnte es z.B. keine HTTP bearbeiten.
> > Die Tatsache, dass die ganze Welt 8-Bit orientiert ist, und
> > dass ein Versuch, dass zu ändern, ist vollig unrealistisch.
> 32 ist ein Vielfaches von 8.
Und? 32 != 8.
> Und mein Prozessor und auch mein C++-Compiler sind 32 bit
> orientiert. Die Tendenz geht zu mehr. Die menschliche Schrift
> sollte wichtig genug sein um gleicht richtig kodiert zu
> werden. Für numerische Operationen nimmt man ja auch ints wo
> chars locker gereicht hätten.
Und? Es geht hier nicht um numerische Operationen. Es geht um
die Tatsache, dass fast alles, überall, 8-Bit orientiert ist.
> > dem, was du im Programm tust, ist es sinnvoll, UTF-32 bzw.
> > UTF-16 intern im Programm zu verwenden (obwohl für die
> > meisten Sachen, die ich mache, funktionniert UTF-8 genau so
> > gut, wenn nicht besser), aber sofort mit der Außenwelt
> > kommuniziert wird, geht's nur UTF-8.
> Ein großes Problem von UTF-8 ist auch, dass es zuviel kann.
> Es kann Alt-Phönizisch etc. und damit bringts du einige
> Programme durcheinander.
Warum? Und wie ist das anders als mit UTF-32?
> Es kann zuviel. Und damit muss ein möglicher Zeichensatz immer
> extra eingeschränkt werden. Bei "ISO 8859-1" weiss ich *genau*
> was ich bekomme, da die Möglichkeiten die ich geg. Abprüfen
> muss uberschaubar sind.
Ob UTF-8 oder ISO 8859-1 musst du wohl überprüfen, was du
bekommen hast. Da sehe ich eigentlich wenig Unterschied, außer
der Tatsache, dass ISO 8859-1 immer auf einer Einheit bleibt;
mit UTF-8 musst du wohl berücksichtigen, dass ein Zeichen
mehrere Bytes verlangen kann. In den Fällen, wo das ein Problem
ist, soll man überlegen, ob es sinnvoller wird, das UTF-8 in
UTF-16 bzw. UTF-32 umzucodieren. Aber dann nur für die interne
Behandlung.
Meinst du wirklich UTF-16, also 2 oder 4 Bytes pro Zeichen, oder UCS-2?
> wobei 'LPTSTR' nach:
> typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
> typedef __nullterminated WCHAR *NWPSTR, *LPWSTR, *PWSTR;
> typedef LPWSTR PTSTR, LPTSTR;
> aufgelöst wird.
Mich stört dabei schon die konsequente Verwendung von Großbuchstaben.
Bastian
> Der Internet ist 8-Bit orientiert. Die meisten Filesysteme auch.
> Um �berall benutzbar zu sein, muss auch eine Codierung 8-Bit
> orientiert sein.
Was meinst du mit "8-bit-orientiert"?
Mail sind auch 7 bit orientiert. Nicht umsonst wurde base64 erfunden.
Abgesehen davon hindert keine 8-bit Orientierung eine logische
Orientierung auf Vielfache von 8.
> Doch. Amsonsten k�nnte es z.B. keine HTTP bearbeiten.
Java kann kein UTF.8. Lediglich ein Subset von UTF-8.
Alt-Ph�nizisch und BOM f�hrt zu Datenm�ll.
> Und? 32 != 8.
32 % 8 == 0
> Und? Es geht hier nicht um numerische Operationen. Es geht um
> die Tatsache, dass fast alles, �berall, 8-Bit orientiert ist.
Nochmal: Was meinst du mit "8-bit-orientiert"?
UTF-8 ist nicht 8bit orientiert. Sondern 8 bis 32 bit orientiert.
Dazu gehen aufgrund der Codierung im Gegensatz zu einem UTF-32 einige
m�gliche Werte verloren.
> Warum? Und wie ist das anders als mit UTF-32?
Weil Java und einige andere Editoren, die vorgeben mit UTF-8
klarzukommen, eben nur ein Subset beherrschen. Gew�hnlich das was mit
16bit Unitcode identisch ist.
> Ob UTF-8 oder ISO 8859-1 musst du wohl �berpr�fen, was du
> bekommen hast. Da sehe ich eigentlich wenig Unterschied, au�er
> der Tatsache, dass ISO 8859-1 immer auf einer Einheit bleibt;
> mit UTF-8 musst du wohl ber�cksichtigen, dass ein Zeichen
> mehrere Bytes verlangen kann. In den F�llen, wo das ein Problem
> ist, soll man �berlegen, ob es sinnvoller wird, das UTF-8 in
> UTF-16 bzw. UTF-32 umzucodieren. Aber dann nur f�r die interne
> Behandlung.
Was ich vermisse ist ein definiertes normiertes Subset.
Z.B. UFT-8-Latin wo alles was in lateinischer Schrift vorkommen codiert
ist. Also alles was mit Lateinischen Schrifts�tzen (u.a. durch weglassen
diverser Akzents etc.) darstellbar ist.
Und so *garantiert* dass nix kyrillisches oder eben Alt-Ph�nizisches
kommt. Und klingonisch gibts zwar unter ISO-639-2 aber nicht im UTF-8
Standard...da sa� wohl kein Trecki im Normierungskommitee...
Diese Form der main-Funktion ist sowieso ein Krampf:
hInstance - wieso nicht gleich eine PID? Am Ende kann man das sowieso
für die gleichen Sachen verwenden.
hPrevInstance - ist AFAIK immer 0. Wozu dann?
lpCmdLine - och nee, ich darf die auch noch selbst in Worte zerlegen?
Nebenbei bemerkt gibt es seit Windows95 keinen Unterschied
zwischen einem short pointer und einem long pointer mehr,
weswegen das 'l' sinnlos ist.
nCmdShow - Noch so ein Witz -- dieser Parameter ist nur für
GUI-Programme von Belang, wird aber an _alle_ ausgeliefert.
Na toll.
Und dann wollen die ja angeblich UTF-16 im Dateisystem unterstützen,
aber wehe, man verwendet mal einen Umlaut im Dateinamen.
>>
>>> Dann ist der Standard wohl nicht mehr ganz zeitgemäß.
>>
>> Wieso. UTF-8 wird zu eine universele Norm, und geht, wo das
>> System es unterstützt. (In Allgemein: wchar_t soll man nur
>> intern benutzen. Sofort Daten das Programm verlassen, gilt char.
>> Das in einem modernen System UTF-8 enthalten kann und soll.)
>
> UTF-16 und UTF-32 sind auch universelle Normen. Ein Unicodezeichen passt
> nunmal nicht in ein Byte. Deshalb sind Typen mit mindestens 2 Byte eben
> besser geeignet.
>
Wie schon beschrieben, passt es auch nicht unbedingt in 2 Byte. Also
spart UTF-8 in jedem Fall mehr Platz als UTF-16.
> Markus
Tschö,
Markus
--
GUI - ein Hintergrundbild und zwölf XTerms
vim -c "exec \"norm iwHFG#NABGURE#IVZ#UNPXRE\"|%s/#/ /g|norm g??g~~"
ich leite das mal um zu den Windowsprogrammieren...
Markus Wichmann wrote:
> Markus Donath <ma_d...@t-online.de> wrote:
>>On 05.08.2009 10:03, James Kanze wrote:
>>>wchar_t** nicht. Die meisten Betriebssysteme unterstützen es
>>>nicht. char** mit UTF-8 funktionniert auf all Unix, die ich
>>>kenne; ich glaube, dass es auch unter Windows geht. (Absolut
>>>portabel kann es nicht sein. Es gibt Systeme, wo Zeichen in
>>>EBCDIC kodiert sind, z.B.)
>>
>>Aber das 'meistverbreitetste' Betriebssystem untertützt es. Mit dem
>>aktuellen MSVC ist es überhaupt kein Problem, UTF-16 Parameter an ein
>>Programm zu übergeben:
>>
>>int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
>>LPTSTR lpCmdLine, int nCmdShow);
>>
>>wobei 'LPTSTR' nach:
>>
>>typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
>>typedef __nullterminated WCHAR *NWPSTR, *LPWSTR, *PWSTR;
>>typedef LPWSTR PTSTR, LPTSTR;
>>
>>aufgelöst wird.
>>
>>Nur ist das natürlich nicht standardkonform.
>
> Diese Form der main-Funktion ist sowieso ein Krampf:
>
> hInstance - wieso nicht gleich eine PID? Am Ende kann man das sowieso
> für die gleichen Sachen verwenden.
Einige Aufrufe benutzen ein HINSTANCE, aber kaum einer eine PID.
> hPrevInstance - ist AFAIK immer 0. Wozu dann?
Kompatibilität....
> lpCmdLine - och nee, ich darf die auch noch selbst in Worte zerlegen?
> Nebenbei bemerkt gibt es seit Windows95 keinen Unterschied
> zwischen einem short pointer und einem long pointer mehr,
> weswegen das 'l' sinnlos ist.
Als kleinen Anreiz dazu, Unicode-Programme zu schreiben, enthält das
Win32-API eine Funktion 'CommandLineToArgvW' (aber keine Funktion
'CommandLineToArgvA' für "ANSI"-Programme).
Selberparsen ist unter Windows schon deswegen angesagt, weil es zum
guten Ton gehört, dass jedes Programm seine eigenen Globbing- und
Quotingregeln mitbringt.
> nCmdShow - Noch so ein Witz -- dieser Parameter ist nur für
> GUI-Programme von Belang, wird aber an _alle_ ausgeliefert.
> Na toll.
Korrigier mich, wenn ich mich irre, aber meine nicht-GUI-Programme
enthalten ganz normal eine 'main'-Funktion, keine 'WinMain'.
> Und dann wollen die ja angeblich UTF-16 im Dateisystem unterstützen,
> aber wehe, man verwendet mal einen Umlaut im Dateinamen.
Das funktioniert schon. 'CreateFileW(L"\u1234", ...)', kein Problem. Nur
das ganze durch die 8-bit-Kommandozeile zu schleusen macht keinen Spaß.
Überhaupt scheitert sogar Microsoft an der Kommandozeile: "Москва.doc"
im Explorer doppelklicken scheitert mit einer Fehlermeldung von Word,
"??????.doc" nicht öffnen zu können, mit Word->Datei->Öffnen geht's aber
ganz normal.
>>>>Dann ist der Standard wohl nicht mehr ganz zeitgemäß.
>>>
>>>Wieso. UTF-8 wird zu eine universele Norm, und geht, wo das
>>>System es unterstützt. (In Allgemein: wchar_t soll man nur
>>>intern benutzen. Sofort Daten das Programm verlassen, gilt char.
>>>Das in einem modernen System UTF-8 enthalten kann und soll.)
>>
>>UTF-16 und UTF-32 sind auch universelle Normen. Ein Unicodezeichen passt
>>nunmal nicht in ein Byte. Deshalb sind Typen mit mindestens 2 Byte eben
>>besser geeignet.
>
> Wie schon beschrieben, passt es auch nicht unbedingt in 2 Byte. Also
> spart UTF-8 in jedem Fall mehr Platz als UTF-16.
Das kommt ganz auf die Sprache an. CJK braucht in UTF-8 eben drei Bytes
pro Zeichen und damit mehr als UTF-16. Bei Kyrillisch ist es egal, und
für uns Westeuropäer ist UTF-8 immer eine Ersparnis gegenüber UTF-16.
Stefan
> > Der Internet ist 8-Bit orientiert. Die meisten Filesysteme
> > auch. Um überall benutzbar zu sein, muss auch eine
> > Codierung 8-Bit orientiert sein.
> Was meinst du mit "8-bit-orientiert"?
> Mail sind auch 7 bit orientiert. Nicht umsonst wurde base64
> erfunden.
Das galt in der Vergangenheit; heute weiß ich nicht. (News war
auch in der Vergangenheit nur 7 Bits; heute aber sind 8 Bits
überall erlaubt.) Und base64 definiert, wie man ein Strom von
Bytes in druckbare ASCII-Zeichen umwandelt. Ein Strom von 8 Bit
Bytes.
> Abgesehen davon hindert keine 8-bit Orientierung eine logische
> Orientierung auf Vielfache von 8.
Man könnte wohl ein Protokoll definieren, das mit 32 Bits
arbeitet. Es gibt sogar Stelle in IP und TCP, wo das dem Fall
ist. überall wo Text erwartet ist, aber, spezifieren die
unterschiedenen Protokolle 8 Bit Bytes.
> > Doch. Amsonsten könnte es z.B. keine HTTP bearbeiten.
> Java kann kein UTF.8. Lediglich ein Subset von UTF-8.
> Alt-Phönizisch und BOM führt zu Datenmüll.
Soweit ich weiß, ist das falsch. (Ich habe leider kein Text in
Alt-Phönizisch, um est zu testen. Aber das soll nicht anders
sein als Chinesisch, die auch Zeichen außerhal dem BMP
verlangt.)
> > Und? 32 != 8.
> 32 % 8 == 0
Und?
> > Und? Es geht hier nicht um numerische Operationen. Es geht
> > um die Tatsache, dass fast alles, überall, 8-Bit orientiert
> > ist.
> Nochmal: Was meinst du mit "8-bit-orientiert"?
> UTF-8 ist nicht 8bit orientiert. Sondern 8 bis 32 bit
> orientiert. Dazu gehen aufgrund der Codierung im Gegensatz zu
> einem UTF-32 einige mögliche Werte verloren.
UTF-8 spefiziert eine Reihe von 8-Bit Bytes.
> > Warum? Und wie ist das anders als mit UTF-32?
> Weil Java und einige andere Editoren, die vorgeben mit UTF-8
> klarzukommen, eben nur ein Subset beherrschen. Gewöhnlich das
> was mit 16bit Unitcode identisch ist.
Es gibt kein 16bit "Unicode". Unicode bestimmt Zeichencodes
zwischen 0 und 0x10FFFF. Die in unterschiedenen "Encoding
Forms" dargestellt dürfen: UTF-32, UTF-16 und UTF-8. Wenn man
nur Byte-orientiert arbeiten kann, wie auf dem Internet, muß man
dazu einen Transformation Format, e.g. UTF-32BE, u.s.w.
benützen.
> > Ob UTF-8 oder ISO 8859-1 musst du wohl überprüfen, was du
> > bekommen hast. Da sehe ich eigentlich wenig Unterschied,
> > außer der Tatsache, dass ISO 8859-1 immer auf einer Einheit
> > bleibt; mit UTF-8 musst du wohl berücksichtigen, dass ein
> > Zeichen mehrere Bytes verlangen kann. In den Fällen, wo das
> > ein Problem ist, soll man überlegen, ob es sinnvoller wird,
> > das UTF-8 in UTF-16 bzw. UTF-32 umzucodieren. Aber dann nur
> > für die interne Behandlung.
> Was ich vermisse ist ein definiertes normiertes Subset. Z.B.
> UFT-8-Latin wo alles was in lateinischer Schrift vorkommen
> codiert ist. Also alles was mit Lateinischen Schriftsätzen
> (u.a. durch weglassen diverser Akzents etc.) darstellbar ist.
> Und so *garantiert* dass nix kyrillisches oder eben
> Alt-Phönizisches kommt. Und klingonisch gibts zwar unter
> ISO-639-2 aber nicht im UTF-8 Standard...da saß wohl kein
> Trecki im Normierungskommitee...
Allgemeiner: ich hätte gerne einen Format, die nur Zeichen
erlaubt, die ich handeln kann. Die z.B. in den Fonts vorkommen,
denen ich zur Verfügung habe. Leiter ist das nicht so einfach,
dann die Unicode Consortium weiß nicht, welchen Fonts ich zur
Verfügung habe. Ich hätte es auch gern, wenn ich nur mit NFC zu
tun hätte, und nur mit Zeichen, die mittels ein einziges
Codepoint in NFC darstellbar sind.
Q: What is the definition of UTF-8?
A. UTF-8 is the byte-oriented encoding form of Unicode. ...
siehe http://unicode.org/faq/utf_bom.html#utf8-1
To meet the requirements of byte-oriented, ASCII-based systems, a third
encoding form is
specified by the Unicode Standard: UTF-8. This variable-width encoding
form preserves
ASCII transparency by making use of 8-bit code units.
siehe http://www.unicode.org/versions/Unicode5.0.0/ch02.pdf#G13708
Seite 32
> Dazu gehen aufgrund der Codierung im Gegensatz zu einem UTF-32 einige
> m�gliche Werte verloren.
>
Wie kommst du darauf?
All three encoding forms can be used to represent the full range of
encoded characters in
the Unicode Standard; they are thus fully interoperable for
implementations that may
choose different encoding forms for various reasons. Each of the three
Unicode encoding
forms can be efficiently transformed into either of the other two
without any loss of data.
siehe http://www.unicode.org/versions/Unicode5.0.0/ch02.pdf#G13708
Seite 29
Lars
> Und base64 definiert, wie man ein Strom von
> Bytes in druckbare ASCII-Zeichen umwandelt.
Ich weiss, was base64 ist. Ich habe bis es f�r Java apache.compress gab
selber einen Parser geschrieben, weil der Sun-Parser buggy war.
Auch f�r C++.
> Man k�nnte wohl ein Protokoll definieren, das mit 32 Bits
> arbeitet.
Yup.
Das meinte ich. Es ist Zeit fpr 32bit.
>> Java kann kein UTF.8. Lediglich ein Subset von UTF-8.
>> Alt-Ph�nizisch und BOM f�hrt zu Datenm�ll.
> Soweit ich wei�, ist das falsch.
Probiers aus!
Ich habs ausprobiert. Sonst w�rde ich nicht so "die Klappe aufreissen".
UFT-8 macht bei uns bei Schnittstellen immer Probleme.
>> 32 % 8 == 0
> Und?
Das zielte darauf ab, dass 32bit ein ganzes Vielfaches von 8 bit sind.
Man also �berall da wo 8bit verlangt werden 32 bit nehmen kann.
Lediglich L�ngenangaben von Strings m�ssen halt mit 4 multipliziert
werden. Aber in dem Fall geht eh kein UTF-8.
> UTF-8 spefiziert eine Reihe von 8-Bit Bytes.
Falsch.
Es speziefiert ein Enconding dessen unterer Teil 8 bits hat.
Und lustigerweise habe *die* wo es stimmt auch nur 7 bit!
> Allgemeiner: ich h�tte gerne einen Format, die nur Zeichen
> erlaubt, die ich handeln kann. Die z.B. in den Fonts vorkommen,
> denen ich zur Verf�gung habe.
Exakt das!
> Leiter ist das nicht so einfach,
> dann die Unicode Consortium wei� nicht, welchen Fonts ich zur
> Verf�gung habe.
Es weiss aber, dass du nur mit lateinischen Zeichen handelst oder nur
mit kyrillischen etc.
Oder eben auch nur mit Alt-Ph�nizisch.
Aber dann eben definiert.
Und das *definierte* ist der Punkt.
Java macht wohl, weil sie "Unicode = 16 bit" setzen, kein richtiges
UTF-8, und man hat das Ergebnis nachtr�glich als CESU-8 "normiert".
> UFT-8 macht bei uns bei Schnittstellen immer Probleme.
Da habe ich die exakt gegenteiligen Erfahrungen.
UTF-8 geht durch existierende Schnittstellen (einschlie�lich der C++-
Standardbibliothek, um marginal ontopic zu bleiben) einfach durch. F�r
32-bit-Schnittstellen m�sste man alles aufbohren.
Wir haben hier z.B. eine C-/C++-Standardbibliothek, unter der ein
posixoides Syscall-Interface liegt (open, readdir, usw.). Das Syscall-
Interface hab ich an einem Nachmittag auf UTF-8 umgestellt, und schon
konnte die dar�berliegende Applikation Unicode benutzen. Mit einer
32-bit-Schnittstelle h�tte ich jetzt die komplette Bibliothek neu machen
d�rfen. Dazu kommt, dass externe Interfaces (in diesem Fall z.B. die
serielle Konsole) eh 8-bit-basiert ist, und man sp�testens dort
"irgendwie" codieren muss.
Letztlich funktioniert eben auch sehr viel existierender Code gut genug.
Zum Beispiel die Funktion 'glob': letztlich findet die ein paar
Metazeichen aus dem ASCII-Satz und spaltet Parameter an '/' auf, aber
prinzipiell funktioniert die aus dem Stand erstmal. Klar, nicht 100%
perfekt: '?' matcht nicht auf ein UTF-8-codiertes '�', und auch das
UTF-8-codierte '[���]' wird wohl nicht verstanden, aber f�r die h�ufigen
Anwendungsf�lle, "ls *.c", tut's.
Die Stelle, wo ich die Anwendung wirklich anfassen musste, um sie zum
Weiterarbeiten zu bewegen, waren sehr �bersichtlich. Im Prinzip nur die
Stellen, wo Text an einen Textrenderer gegeben wird.
>> Allgemeiner: ich h�tte gerne einen Format, die nur Zeichen
>> erlaubt, die ich handeln kann. Die z.B. in den Fonts vorkommen,
>> denen ich zur Verf�gung habe.
>
> Exakt das!
Allerdings ist es nun auch nicht besonders klever, so ein Encoding zu
erfinden und dann in eine Mail reinzuschreiben
Content-Encoding: text/plain; charset=james-sein-font
Da behandelt man halt die Unicode-Zeichen, die man kann, so gut es geht,
und aus den anderen werden so lustige K�stchen gemacht. Ich will
jedenfalls nicht st�ndig mein Encoding �ndern, wenn ich mal wieder 'nen
Nachmittag lang Buchstaben gemalt habe.
Stefan
> >> Soweit ich weiß, ist das falsch.
> > Probiers aus! Ich habs ausprobiert. Sonst würde ich nicht
> > so "die Klappe aufreissen".
Laut der Spezifikation der API, »new
java.io.InputStreamReader( new FileInputStream( "filename" ),
"UTF-8" )« soll's tun. Wenn nicht, dann hat deine
Implementierung einen Fehler. Es geht bei mir (Java 1.6.0_12,
von Sun, unter Linux): meine Quelldatei enthält:
C3 A9 74 C3 A9 0A F0 A0 80 80 0A
und ein Dump der gelesenen Zeichen gibt:
00E9 0074 00E9 000A D840 DC00 000A
, genau was ich erwarte.
> Java macht wohl, weil sie "Unicode = 16 bit" setzen, kein
> richtiges UTF-8, und man hat das Ergebnis nachträglich als
> CESU-8 "normiert".
Java benutzt, intern, UTF-16. Wenn er nach außen schreibt, kommt
es darauf an; wenn er ein String persistent macht (binärische
Daten), dann schreibt und liest er UTF-16BE (wieder ein
Byte-orientiertes Format), amsonsten schreibt und liest er, was
du als Codierung spezifiziert. Selbstverständlich nur dann,
wenn die Codierung unterstützt wird, aber "Every implementation
of the Java platform is required to support the following
standard charsets. [...] UTF-8 [...]".
> > UFT-8 macht bei uns bei Schnittstellen immer Probleme.
> Da habe ich die exakt gegenteiligen Erfahrungen.
> UTF-8 geht durch existierende Schnittstellen (einschließlich
> der C++- Standardbibliothek, um marginal ontopic zu bleiben)
> einfach durch. Für 32-bit-Schnittstellen müsste man alles
> aufbohren.
Das entspricht mehr oder weniger meine Erfahrung auch. Das
Problem ist nicht einfach; unter Unix, z.B. verwaltet X die
Codierung der Anzeigefonts; von deinem Programm aus hast du kaum
einen Einfluß. Aber was überhaupt nirgendwo funktionniert, sind
nicht Byte-orientierten Codierungen, wie UTF-16 oder UTF-32; da
hast du sofort Probleme mit der Byteordnung, und einige
Schnittstellen haben auch Probleme mit den '\0' oder andere
Steuerzeichen, die sie sehen, weil sie die einzige UTF-16
Zeichen als zwei getrennte Bytes betrachten.
[...]
> >> Allgemeiner: ich hätte gerne einen Format, die nur Zeichen
> >> erlaubt, die ich handeln kann. Die z.B. in den Fonts
> >> vorkommen, denen ich zur Verfügung habe.
> > Exakt das!
> Allerdings ist es nun auch nicht besonders klever, so ein
> Encoding zu erfinden und dann in eine Mail reinzuschreiben
> Content-Encoding: text/plain; charset=james-sein-font
> Da behandelt man halt die Unicode-Zeichen, die man kann, so
> gut es geht, und aus den anderen werden so lustige Kästchen
> gemacht. Ich will jedenfalls nicht ständig mein Encoding
> ändern, wenn ich mal wieder 'nen Nachmittag lang Buchstaben
> gemalt habe.
Das war mehr oder weniger mein Argument. Nur habe ich es
ironisch dargestellt; ich habe nicht mitgerechnet, dass man eine
Behauptung ernst nehmen könnte, dass Unicode die genaue
Konfigurierung meines Rechners (installierte Fonts)
berücksichtigen soll.
> Allerdings ist es nun auch nicht besonders klever, so ein Encoding zu
> erfinden und dann in eine Mail reinzuschreiben
> Content-Encoding: text/plain; charset=james-sein-font
> Da behandelt man halt die Unicode-Zeichen, die man kann, so gut es geht,
> und aus den anderen werden so lustige K�stchen gemacht. Ich will
> jedenfalls nicht st�ndig mein Encoding �ndern, wenn ich mal wieder 'nen
> Nachmittag lang Buchstaben gemalt habe.
Darum geht es gar nicht.
Stell dir vor du bist Firma XY und hast als Realisierer einen Vertrag
mit dem Finanzamt um die Formulare zu erstellen. Das zuliefernede System
mit den Daten liefert lasu Schnittstellenvereinbahrung ISO 8859-1. Dein
Formularrenderer kommt mit jedem Zeichen aus ISO 8859-1 klar.
Ihr vereinbart UFT-8. Jetzt kann das zuliefernde System alles aus UTF-8
liefern. Und irgendwann wird es nicht nur deutsche �s und �s UTF-8
kodieren, sondern tats�chlich kyrillische Zeichen senden. Dein System
kackt ab, die Finanzamt-IT steht mehrere Tage. Skandal. Rat mal wer den
schwarzen Peter bekommt? Du hast schliesslich zugesichert UTF-8 zu
k�nnen. Du hast es nicht eingehalten.
Das Beispiel ist so aus der Praxis. Allerdings nicht mit Finanzamt,
nicht mit kyrillisch. Aber ansonsten schon so.
Das ist jetzt aber wirklich kein Problem von UTF-8. Das hat du mit jeder
anderen Kombination von Zeichens�tzen genauso. Selbst mit solchen
Banalit�ten wie Latin-1 vs. Windows-1252; in der versch�rften Version
sieht das dann so aus, dass du ein HTML-Dokument bekommst, das behaup-
tet, Latin-1 zu sein, aber v�llig (HTML-5-)Spec-konform Windows-1252
enth�lt (alternativ bekommst du das spezifikationswidrig, wie z.B. bei
ID3-Tags, wirst aber trotzdem vom Kunden angemault, die Euro-Zeichen
nicht decodieren zu k�nnen).
Letztlich brauchst du halt immer eine R�ckfallbehandlung f�r nicht
definierte Eingaben, v�llig unabh�ngig, ob du UTF-8 <-> L1 umrechnest
oder CP866 <-> KOI8-R.
Stefan
> Das ist jetzt aber wirklich kein Problem von UTF-8.
> Das hat du mit jeder
> anderen Kombination von Zeichensätzen genauso. Selbst mit solchen
> Banalitäten wie Latin-1 vs. Windows-1252; in der verschärften Version
> sieht das dann so aus, dass du ein HTML-Dokument bekommst, das behaup-
> tet, Latin-1 zu sein, aber völlig (HTML-5-)Spec-konform Windows-1252
> enthält
Wo ist denn da das Problem?
Wenn es Latin-1 sein soll und ein spezielles Windows-1252-Zeichen
kommt,
dann läuft das unter fehlerhaften Input-Daten.
> Letztlich brauchst du halt immer eine Rückfallbehandlung für nicht
> definierte Eingaben
Genau. Aber es geht genau um die exakte Definion der erlaubten
Zeichenmenge.
Und da hilft UTF-8 nicht. Im Gegenteil.
Ich sehe jetzt nicht, wo das nun mit Latin-1 <-> Windows-1252 so enorm
viel einfacher sein soll als mit UTF-8. Klar, in UTF-8 ist es erstmal
etwas komplizierter, aus einem Bytestrom einen Zeichenstrom zu machen,
aber sobald das getan ist, funktioniert es auch nicht anders als bei der
Konvertierung zwischen 1-Byte-Zeichens�tzen.
C++ bietet zugegebenerma�en schon bei 1-Byte-Zeichens�tzen ausreichend
Stolperstellen (Hand aufs Herz: wer castet tats�chlich die Parameter zu
'tolower' oder 'isalpha' immer korrekt?), aber das packt man halt einmal
in eine Bibliothek und fertig.
Stefan