`mbstowcs()` Windows vs. Linux
-
@firefly sagte in `mbstowcs()` Windows vs. Linux:
Du solltest für den windows build besser MultiByteToWideChar verwenden statt mbstowcs. Dadurch wird definitiv der input als utf-8 interpretiert.
Jetzt habe ich mal ein sauberes Testprogramm gemacht.
setlocale(LC_ALL, "")
scheint recht wichtig zu sein. Ansonsten gibt es zumindest unter Linux einSIGESV.
Das Testprogramm:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <locale.h> #if defined(_WIN64) #include <windows.h> #endif void WideChar_Test(const char * str){ printf("wchar_t size: %li\n",sizeof(wchar_t)); printf("UTF8: (%li) ", strlen(str)); for (int i=0; i<strlen(str); i++) { printf("%hhu - ", str[i]); } printf("\n"); size_t len = mbstowcs(nullptr, str, strlen(str)); wchar_t * wc = (wchar_t *) malloc(len * sizeof(wchar_t)); mbstowcs(wc, str, len); printf("WideStr: (%li) ", len); for (int i=0; i<len; i++) { printf("%hhu - ", wc[i]); } printf("\n\n"); free(wc); } const char * TestString1 = "12345678"; const char * TestString2 = "ABCÄÖÜŸ"; #if defined(_WIN64) void WideChar_Windows(const char * str){ printf("wchar_t size: %li\n",sizeof(wchar_t)); printf("UTF8: (%li) ", strlen(str)); for (int i=0; i<strlen(str); i++) { printf("%hhu - ", str[i]); } printf("\n"); size_t len = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0); wchar_t * wc = (wchar_t *) malloc(len * sizeof(wchar_t)); MultiByteToWideChar( CP_UTF8, 0, str, -1, wc, len); printf("WideStr: (%li) ", len); for (int i=0; i<len; i++) { printf("%hhu - ", wc[i]); } printf("\n\n"); free(wc); } #endif int main(int argc, char **argv) { printf("Testring 1: %s\n", TestString1); printf("Testring 2: %s\n", TestString2); // printf("setlocale: %s", setlocale(LC_ALL, "de_CH.utf8")); printf("setlocale: %s\n", setlocale(LC_ALL, "")); printf("--- Testring 1 ---\n"); WideChar_Test(TestString1); printf("--- Testring 2 ---\n"); WideChar_Test(TestString2); #if defined(_WIN64) printf("--- MultiByteToWideChar Testring 1 ---\n"); WideChar_Windows(TestString1); printf("--- MultiByteToWideChar Testring 2 ---\n"); WideChar_Windows(TestString2); #endif return 0; }
Das compilieren:
echo echo ======== Linux ======== echo rm main gcc -o main main.cpp ./main echo echo ======== Windows ======== echo rm main.exe x86_64-w64-mingw32-gcc main.cpp -o main.exe wine main.exe
Dies Ausgabe:
$ ./compile.sh ======== Linux ======== Testring 1: 12345678 Testring 2: ABCÄÖÜŸ setlocale: de_CH.UTF-8 --- Testring 1 --- wchar_t size: 4 UTF8: (8) 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - WideStr: (8) 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - --- Testring 2 --- wchar_t size: 4 UTF8: (11) 65 - 66 - 67 - 195 - 132 - 195 - 150 - 195 - 156 - 197 - 184 - WideStr: (7) 65 - 66 - 67 - 196 - 214 - 220 - 120 - ======== Windows ======== 002c:fixme:winediag:loader_init wine-staging 9.9 is a testing version containing experimental patches. 002c:fixme:winediag:loader_init Please mention your exact version when filing bug reports on winehq.org. Testring 1: 12345678 Testring 2: ABCà Ãß setlocale: German_Switzerland.1252 --- Testring 1 --- wchar_t size: 2 UTF8: (8) 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - WideStr: (8) 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - --- Testring 2 --- wchar_t size: 2 UTF8: (11) 65 - 66 - 67 - 195 - 132 - 195 - 150 - 195 - 156 - 197 - 184 - WideStr: (11) 65 - 66 - 67 - 195 - 30 - 195 - 19 - 195 - 83 - 197 - 184 - --- MultiByteToWideChar Testring 1 --- wchar_t size: 2 UTF8: (8) 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - WideStr: (9) 49 - 50 - 51 - 52 - 53 - 54 - 55 - 56 - 0 - --- MultiByteToWideChar Testring 2 --- wchar_t size: 2 UTF8: (11) 65 - 66 - 67 - 195 - 132 - 195 - 150 - 195 - 156 - 197 - 184 - WideStr: (8) 65 - 66 - 67 - 196 - 214 - 220 - 120 - 0 -
Was am Anfang schon auffällt, Die Windows Konsole kommt mit UTF8 nicht zurecht.
MultiByteToWideChar
(Windows) undmbstowcs
(Linux) spuckt das gleiche aus.
-
@Mathuas sagte in `mbstowcs()` Windows vs. Linux:
Was am Anfang schon auffällt, Die Windows Konsole kommt mit UTF8 nicht zurecht.
Ja weil windows bei default in der CLI für non "Unicode" (Unter windows ist UNICODE = UTF-16 aka wchar_t) eine ANSI codepage nutzt. Du musst die windows console explizit in den utf-8 modus schalten (afaik durch das setzen einer passenden codepage in der windows console.
Wobei das AFAIK jetzt nur für die cmd.exe gilt.
MultiByteToWideChar scheint jetzt auch zu funktionieren. mbstowcs Kommt unter Windows nicht zurecht.
Öhm wieso mbstowcs nicht funktioniert hab ich dir schon geschrieben...
Und in deiner ausgabe für den windows build siehst du es auch:setlocale: German_Switzerland.1252
das ist keine utf-8 locale... Sondern eine ANSI codepage locale...
ABer das ganze habe ich dir schon mitgeteilt aber scheinbar ignorierst du diese Informationen komplett...
-
Ich habe die Beispiel von hier probiert, bei Windows spuckt es überall
(null)
.https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?view=msvc-170
Ausser wen ich es ausschreibe wie hier:
printf("setlocale: %s\n", setlocale(LC_ALL, "German_Switzerland.1252"));
Sowas geht nicht
".UTF8"
-
Versuche es mal beim Aufruf anzugeben, s. Changing the Locale in WINE, anstatt mittels
setlocale
im Code:
LANG="de_CH.UTF8" wine main.exe
bzw.
LC_ALL="de_CH.UTF8" wine main.exe
(hier benutzt du die Linux-Nomenklatur, anstatt im Code die Windows-Runtime Nomenklatur)
-
entweder ist das eine eigenart von wine, mingw oder du machst was falsch...
Folgender code unter windows mit visual studio 2019 liefert non null zurück:
#include <stdio.h> #include <locale.h> int main(void) { printf("setlocale: %s\n", setlocale(LC_ALL, ".UTF8")); return 0; }
-
@Th69 sagte in `mbstowcs()` Windows vs. Linux:
Versuche es mal beim Aufruf anzugeben, s. Changing the Locale in WINE, anstatt mittels
setlocale
im Code:
LANG="de_CH.UTF8" wine main.exe
bzw.
LC_ALL="de_CH.UTF8" wine main.exe
(hier benutzt du die Linux-Nomenklatur, anstatt im Code die Windows-Runtime Nomenklatur)Nützt ihm aber nicht viel wenn er sein Programm unter einem richtigne windows laufen lassen möchte..
-
Das ist ja auch ersteinmal als Test gedacht, ob es mit Wine so funktioniert.
Ansonsten müßte er sein Programm unter einem echten Windows 10/11 (z.B. in einer VM) laufen lassen, da ".UTF8" erst dort eingeführt wurde:Ab Windows 10, Version 1803 (10.0.17134.0), unterstützt die universelle C-Runtime die Verwendung einer UTF-8-Codepage.
Und wenn ich die Doku richtig verstehe, so müßte man unter Windows den Bindestrich (statt Unterstrich) verwenden, z.B.
"de-CH.UTF8"
.
-
@firefly sagte in `mbstowcs()` Windows vs. Linux:
entweder ist das eine eigenart von wine, mingw oder du machst was falsch...
Folgender code unter windows mit visual studio 2019 liefert non null zurück:
#include <stdio.h> #include <locale.h> int main(void) { printf("setlocale: %s\n", setlocale(LC_ALL, ".UTF8")); return 0; }
Ich habe dies gerade in der VB mit Win10 probiert. Es kommt auch
(null)
Compiliert habe ich es mit wingw32x86_64-w64-mingw32-gcc main.cpp -o main.exe
Mit einem
(LC_ALL, "")
spuckt es in wine und VB-Win10 das gleiche aus:setlocale: German_Switzerland.1252
-
Es ist ein mingw problem.
https://stackoverflow.com/questions/73185769/build-a-program-with-mingw-on-linux-and-run-under-wine-utf-8-supportWEnn ich folgenden code unter windows mit visual studio (als mit dem microsoft compiler) im release build baue (unter Windows 10 22H2) und dann das binary unter linux mit wine starte funktioniert es:
#include <stdio.h> #include <locale.h> int main(void) { printf("setlocale: %s\n", setlocale(LC_ALL, ".utf8")); printf("%s\n", "\xc5\xb8\x41\xc3\x84\xc3\x96\xc3\x9c"); return 0; }
Output:
setlocale: English_United Kingdom.65001 ŸAÄÖÜ
Beachte die .65001 statt .1252 am ende der locale ausgabe.
65001 ist die codepage nummer für UTF-8
-
@firefly sagte in `mbstowcs()` Windows vs. Linux:
WEnn ich folgenden code unter windows mit visual studio (als mit dem microsoft compiler) im release build baue (unter Windows 10 22H2) und dann das binary unter linux mit wine starte funktioniert es:
Recht merkwürdig
setlocale
ist doch in dermsvcrt.dll
. Somit müssten doch beide Kompilate das gleiche Ergebnis liefern. Oder übersehe ich das etwas ?
-
@Mathuas sagte in `mbstowcs()` Windows vs. Linux:
@firefly sagte in `mbstowcs()` Windows vs. Linux:
WEnn ich folgenden code unter windows mit visual studio (als mit dem microsoft compiler) im release build baue (unter Windows 10 22H2) und dann das binary unter linux mit wine starte funktioniert es:
Recht merkwürdig
setlocale
ist doch in dermsvcrt.dll
. Somit müssten doch beide Kompilate das gleiche Ergebnis liefern. Oder übersehe ich das etwas ?Ja denn die "alte" C-Runtime (via msvcrt.dll) von Windows unterstützt kein UTF-8.
Sondern erst mit der "neuen" C-Runtime (UCRT) wird UTF-8 in der C-Runtime unterstützt.Wie man hier sehen kann
https://gist.github.com/minoki/c3d65d15982f17db0801e8a9b06333bf
(siehe die ausgaben wo versucht wird eine UTF-8 locale zu setzen.Oder auch hier beschrieben:
https://blog.r-project.org/2022/11/07/issues-while-switching-r-to-utf-8-and-ucrt-on-windows/https://stackoverflow.com/questions/67848972/differences-between-msvcrt-ucrt-and-vcruntime-libraries
Und deine mingw version nutzt die "alte" MS C-Runtime
-
@firefly sagte in `mbstowcs()` Windows vs. Linux:
Ja denn die "alte" C-Runtime (via msvcrt.dll) von Windows unterstützt kein UTF-8.
Sondern erst mit der "neuen" C-Runtime (UCRT) wird UTF-8 in der C-Runtime unterstützt.Wen ich es richtig verstehe, müsste man
ucrtbase.dll
einbinden ?
-
Kannst es ja mal mit dem DependencyWalker für die kompilierte Datei überprüfen.
Ansonsten habe ich für LLVM/Clang/LLD (anstatt gcc) unter github.com/mstorsjo/llvm-mingw UCRT-Support gefunden, d.h. Download der neuesten Version unter Releases.
-
@Th69 sagte in `mbstowcs()` Windows vs. Linux:
Kannst es ja mal mit dem DependencyWalker für die kompilierte Datei überprüfen.
Danke
Cooles Programm. Ich musste noch dieMFC42.dll
runterladen.Gibt es so etwas auch für Linux ?
-
Such doch einfach mal nach "Linux Dependency Walker"...
-
@Mathuas ldd
-
@Tyrdal
DankeIch habe gerade noch etwas genialeres entdeckt. Dies kommt fast an das von "Linux Dependency Walker" ran.
https://github.com/haampie/libtree
Es ist sogar bei Ubuntu dabei.
sudo apt install libtree
-
@Mathuas sagte in `mbstowcs()` Windows vs. Linux:
sudo apt install libtree
Danke auch für den Tip. Die Darstellung ist echt deutlich angenehmer zu lesen. Bei Debian ist es übrigens auch dabei.
-
@Finnegan sagte in `mbstowcs()` Windows vs. Linux:
Danke auch für den Tip. Die Darstellung ist echt deutlich angenehmer zu lesen. Bei Debian ist es übrigens auch dabei.
Mit diesen Parametern ist es recht ausführlich:
libtree /bin/ls -vvv -p
Einzig was mich stört. Die lila-Schrift ist kaum zu lesen.
-
@firefly sagte in `mbstowcs()` Windows vs. Linux:
@Th69 sagte in `mbstowcs()` Windows vs. Linux:
Versuche es mal beim Aufruf anzugeben, s. Changing the Locale in WINE, anstatt mittels
setlocale
im Code:
LANG="de_CH.UTF8" wine main.exe
bzw.
LC_ALL="de_CH.UTF8" wine main.exe
(hier benutzt du die Linux-Nomenklatur, anstatt im Code die Windows-Runtime Nomenklatur)Nützt ihm aber nicht viel wenn er sein Programm unter einem richtigen windows laufen lassen möchte.
Ich habe male ein wenig
LANG=
rumgespielt. Spannend was da rauskommt.#include <stdio.h> #include <locale.h> #include <time.h> int main(void) { time_t currtime; struct tm *timer; char buffer[80]; time( &currtime ); timer = localtime( &currtime ); printf("\nsetlocale: %s\n", setlocale(LC_ALL, "")); strftime(buffer,80,"%c", timer ); printf("Float: %f Date: %s\n\n", 123.456, buffer) ; return 0; }
Copilierscript:
echo echo ======== Linux ======== echo rm main gcc -o main main.c LANG="de_CH.UTF8" ./main LANG="de_DE.UTF8" ./main LANG="en_US.UTF8" ./main LANG="en_GB.UTF8" ./main echo echo ======== Windows ======== echo rm main.exe x86_64-w64-mingw32-gcc main.c -o main.exe LANG="de_CH.UTF8" wine main.exe LANG="de_DE.UTF8" wine main.exe LANG="en_US.UTF8" wine main.exe LANG="en_GB.UTF8" wine main.exe
Ausgabe:
======== Linux ======== setlocale: de_CH.UTF8 Float: 123.456000 Date: Mo 03 Jun 2024 17:31:02 setlocale: de_DE.UTF8 Float: 123,456000 Date: Mo 03 Jun 2024 17:31:02 CEST setlocale: en_US.UTF8 Float: 123.456000 Date: Mon 03 Jun 2024 05:31:02 PM CEST setlocale: en_GB.UTF8 Float: 123.456000 Date: Mon 03 Jun 2024 17:31:02 CEST ======== Windows ======== setlocale: German_Switzerland.1252 Float: 123.456000 Date: 3.6.2024 17:31:03 setlocale: German_Germany.1252 Float: 123,456000 Date: 3.6.2024 17:31:03 setlocale: English_United States.1252 Float: 123.456000 Date: 6/3/2024 5:31:03 PM setlocale: English_United Kingdom.1252 Float: 123.456000 Date: 03/06/2024 17:31:03
Es wird alles berücksichtigt, inklusive das unsympathische Komma beim Float für die Deutschen.
Was noch interessant ist, wieso kommt das Datum bei wine anders raus als unter Linux ?