Hier gibt es einige sehr gute Antworten, aber ich denke, ich kann einige Dinge in Bezug auf Windows / Visual Studio hinzufügen. Dies basiert auf meinen Erfahrungen mit VS2015. Unter Linux besteht die Antwort im Grunde darin, std::string
überall UTF-8 zu codieren . Unter Windows / VS wird es komplexer. Hier ist warum. Windows erwartet, dass mit char
s gespeicherte Zeichenfolgen mithilfe der Codepage des Gebietsschemas codiert werden. Dies ist fast immer der ASCII-Zeichensatz, gefolgt von 128 weiteren Sonderzeichen, abhängig von Ihrem Standort. Lassen Sie mich nur feststellen, dass dies nicht nur bei Verwendung der Windows-API der Fall ist, sondern dass es drei weitere wichtige Stellen gibt, an denen diese Zeichenfolgen mit Standard-C ++ interagieren. Hierbei handelt es sich um Zeichenfolgenliterale, die ausgegeben werden, um einen Dateinamen zu std::cout
verwenden <<
und an diesen zu übergeben std::fstream
.
Ich werde hier ganz vorne mit dabei sein, dass ich Programmierer und kein Sprachspezialist bin. Ich schätze, dass USC2 und UTF-16 nicht dasselbe sind, aber für meine Zwecke sind sie nahe genug, um austauschbar zu sein, und ich verwende sie hier als solche. Ich bin mir nicht sicher, welches Windows verwendet, aber ich muss es im Allgemeinen auch nicht wissen. Ich habe UCS2 in dieser Antwort angegeben. Es tut mir also im Voraus leid, wenn ich jemanden mit meiner Unkenntnis dieser Angelegenheit verärgert habe, und ich bin froh, sie zu ändern, wenn ich etwas falsch mache.
String-Literale
Wenn Sie Zeichenfolgenliterale eingeben, die nur Zeichen enthalten, die von Ihrer Codepage dargestellt werden können, speichert VS diese in Ihrer Datei mit 1 Byte pro Zeichencodierung basierend auf Ihrer Codepage. Beachten Sie, dass, wenn Sie Ihre Codepage ändern oder Ihre Quelle einem anderen Entwickler mit einer anderen Codepage geben, ich denke (aber nicht getestet habe), dass der Charakter anders enden wird. Wenn Sie Ihren Code auf einem Computer mit einer anderen Codepage ausführen, bin ich mir nicht sicher, ob sich auch das Zeichen ändert.
Wenn Sie Zeichenfolgenliterale eingeben, die nicht durch Ihre Codepage dargestellt werden können, werden Sie von VS aufgefordert, die Datei als Unicode zu speichern. Die Datei wird dann als UTF-8 codiert. Dies bedeutet, dass alle Nicht-ASCII-Zeichen (einschließlich der Zeichen auf Ihrer Codepage) durch 2 oder mehr Bytes dargestellt werden. Dies bedeutet, wenn Sie Ihre Quelle an eine andere Person weitergeben, sieht die Quelle gleich aus. Bevor die Quelle jedoch an den Compiler übergeben wird, konvertiert VS den UTF-8-codierten Text in Codepage-codierten Text, und alle auf der Codepage fehlenden Zeichen werden durch ersetzt ?
.
Die einzige Möglichkeit, die korrekte Darstellung eines Unicode-Zeichenfolgenliterals in VS zu gewährleisten, besteht darin, dem Zeichenfolgenliteral L
ein breites Zeichenfolgenliteral vorangestellt zu machen. In diesem Fall konvertiert VS den UTF-8-codierten Text aus der Datei in UCS2. Sie müssen dieses String-Literal dann an einen std::wstring
Konstruktor übergeben oder es in utf-8 konvertieren und in a einfügen std::string
. Wenn Sie möchten, können Sie die Windows-API-Funktionen verwenden, um sie mithilfe Ihrer Codepage zu codieren, um sie in ein zu setzen. std::string
Möglicherweise haben Sie jedoch auch kein breites Zeichenfolgenliteral verwendet.
std :: cout
Bei der Ausgabe an die Konsole mit können <<
Sie nur verwenden std::string
, nicht std::wstring
und der Text muss mit Ihrer Gebietsschema-Codepage codiert werden. Wenn Sie ein haben std::wstring
, müssen Sie es mit einer der Windows-API-Funktionen konvertieren. Alle Zeichen, die nicht auf Ihrer Codepage enthalten sind, werden durch ersetzt ?
(möglicherweise können Sie das Zeichen ändern, ich kann mich nicht erinnern).
std :: fstream Dateinamen
Das Windows-Betriebssystem verwendet UCS2 / UTF-16 für seine Dateinamen, sodass Sie unabhängig von Ihrer Codepage Dateien mit einem beliebigen Unicode-Zeichen haben können. Dies bedeutet jedoch, dass Sie verwenden müssen, um auf Dateien mit Zeichen zuzugreifen oder diese zu erstellen, die sich nicht auf Ihrer Codepage befinden std::wstring
. Es geht nicht anders. Dies ist eine Microsoft-spezifische Erweiterung std::fstream
, die auf anderen Systemen wahrscheinlich nicht kompiliert werden kann. Wenn Sie std :: string verwenden, können Sie nur Dateinamen verwenden, die nur Zeichen auf Ihrer Codepage enthalten.
Deine Optionen
Wenn Sie nur unter Linux arbeiten, sind Sie wahrscheinlich nicht so weit gekommen. Verwenden Sie UTF-8 einfach std::string
überall.
Wenn Sie nur unter Windows arbeiten, verwenden Sie UCS2 einfach std::wstring
überall. Einige Puristen mögen sagen, dass sie UTF8 verwenden und dann bei Bedarf konvertieren, aber warum sollten sie sich um den Ärger kümmern?
Wenn Sie plattformübergreifend sind, ist es ein Chaos, ehrlich zu sein. Wenn Sie versuchen, UTF-8 unter Windows überall zu verwenden, müssen Sie mit Ihren Zeichenfolgenliteralen und der Ausgabe an die Konsole sehr vorsichtig sein. Sie können Ihre Saiten dort leicht beschädigen. Wenn Sie std::wstring
unter Linux überall verwenden, haben Sie möglicherweise keinen Zugriff auf die breite Version von std::fstream
, sodass Sie die Konvertierung durchführen müssen, aber es besteht kein Risiko einer Beschädigung. Ich persönlich halte dies für eine bessere Option. Viele würden nicht zustimmen, aber ich bin nicht allein - es ist der Weg, den wxWidgets zum Beispiel eingeschlagen hat.
Eine andere Möglichkeit könnte darin bestehen, unicodestring
wie std::string
unter Linux und std::wstring
Windows zu tippen und ein Makro namens UNI () zu haben, das unter Windows L und vor Linux nichts vorstellt, dann den Code
#include <fstream>
#include <string>
#include <iostream>
#include <Windows.h>
#ifdef _WIN32
typedef std::wstring unicodestring;
#define UNI(text) L ## text
std::string formatForConsole(const unicodestring &str)
{
std::string result;
//Call WideCharToMultiByte to do the conversion
return result;
}
#else
typedef std::string unicodestring;
#define UNI(text) text
std::string formatForConsole(const unicodestring &str)
{
return str;
}
#endif
int main()
{
unicodestring fileName(UNI("fileName"));
std::ofstream fout;
fout.open(fileName);
std::cout << formatForConsole(fileName) << std::endl;
return 0;
}
wäre auf jeder Plattform in Ordnung, denke ich.
Antworten
Also, um deine Fragen zu beantworten
1) Wenn Sie für Windows programmieren, dann die ganze Zeit, wenn plattformübergreifend, dann vielleicht die ganze Zeit, es sei denn, Sie möchten sich mit möglichen Korruptionsproblemen unter Windows befassen oder Code mit einer Plattform schreiben, die spezifisch ist #ifdefs
, um die Unterschiede zu umgehen , wenn Sie nur verwenden Linux dann nie.
2) Ja. Außerdem können Sie es unter Linux auch für alle Unicodes verwenden. Unter Windows können Sie es nur für alle Unicodes verwenden, wenn Sie sich für die manuelle Codierung mit UTF-8 entscheiden. Die Windows-API- und Standard-C ++ - Klassen erwarten jedoch std::string
, dass die Codierung mithilfe der Codepage des Gebietsschemas erfolgt. Dies umfasst alle ASCII-Zeichen sowie weitere 128 Zeichen, die sich je nach der von Ihrem Computer eingerichteten Codepage ändern.
3) Ich glaube schon, aber wenn nicht, dann ist es nur ein einfaches typedef eines 'std :: basic_string' mit wchar_t
anstelle vonchar
4) Ein breites Zeichen ist ein Zeichentyp, der größer als der 1-Byte-Standardtyp ist char
. Unter Windows sind es 2 Bytes, unter Linux 4 Bytes.