windows adalah sistem unicode (UTF-16). konsol unicode juga. jika Anda ingin mencetak teks unicode - Anda perlu (dan ini paling efektif) menggunakan WriteConsoleW
BOOL PrintString(PCWSTR psz)
{
DWORD n;
return WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), psz, (ULONG)wcslen(psz), &n, 0);
}
PrintString(L"—");
dalam hal ini dalam file biner Anda akan berupa karakter lebar —
(2 byte 0x2014
) dan konsol mencetaknya apa adanya.
jika fungsi ansi (multi-byte) dipanggil untuk konsol keluaran - seperti WriteConsoleA
atau WriteFile
- konsol terlebih dahulu menerjemahkan string multi-byte ke unicode melalui MultiByteToWideChar
dan sebagai gantinya CodePage akan digunakan nilai yang dikembalikan oleh GetConsoleOutputCP
. dan di sini (terjemahan) bisa menjadi masalah jika Anda menggunakan karakter > 0x80
pertama-tama kompiler dapat memberi Anda peringatan: File berisi karakter yang tidak dapat diwakili dalam halaman kode saat ini (angka). Simpan file dalam format Unicode untuk mencegah kehilangan data. (C4819). tetapi bahkan setelah Anda menyimpan file sumber dalam format Unicode, bisa menjadi yang berikutnya:
wprintf(L"ù"); // no warning
printf("ù"); //warning C4566
karena L"ù"
disimpan sebagai string karakter lebar (sebagaimana adanya) dalam file biner - di sini semuanya baik-baik saja dan tidak ada masalah dan peringatan apa pun. tetapi "ù"
disimpan sebagai char string (string byte tunggal). kompiler perlu mengonversi string lebar "ù" dari file sumber menjadi string multi-byte dalam file biner (.obj, dari mana linker membuat pe daripada). dan penggunaan kompiler untuk ini WideCharToMultiByte
< /a> dengan CP_ACP (Halaman kode ANSI Windows default sistem saat ini.)
jadi apa yang terjadi jika Anda mengatakan panggil printf("ù");
?
- string unicode "ù" akan dikonversi menjadi multi-byte
WideCharToMultiByte(CP_ACP, )
dan ini akan dilakukan pada waktu kompilasi. string multi-byte yang dihasilkan akan disimpan dalam file biner
- konsol itu run-time ubah string multi-byte Anda menjadi karakter lebar sebesar
MultiByteToWideChar(GetConsoleOutputCP(), ..)
dan cetak string ini
jadi Anda mendapat 2 konversi: unicode -> CP_ACP -> multi-byte -> GetConsoleOutputCP() -> unicode
secara default GetConsoleOutputCP() == CP_OEMCP != CP_ACP
meskipun Anda menjalankan program di komputer tempat Anda mengkompilasinya. (di komputer lain dengan CP_OEMCP
lain khususnya)
masalah dalam konversi yang tidak kompatibel - halaman kode berbeda yang digunakan. tetapi bahkan jika Anda mengubah halaman kode konsol ke CP_ACP
- konversi tetap dapat salah menerjemahkan beberapa karakter.
dan tentang CRT api wprintf
- berikut situasinya:
wprintf
pertama mengonversi string yang diberikan dari unicode ke multi-byte dengan menggunakannya arus internal locale (dan perhatikan bahwa lokal crt tidak bergantung pada lokal dan berbeda dengan lokal konsol). lalu panggil WriteFile
dengan string multi-byte. konsol ubah kembali string multi-byte ini menjadi unicode
unicode -> current_crt_locale -> multi-byte -> GetConsoleOutputCP() -> unicode
jadi untuk menggunakan wprintf
pertama-tama kita perlu menyetel lokal crt saat ini ke GetConsoleOutputCP()
char sz[16];
sprintf(sz, ".%u", GetConsoleOutputCP());
setlocale(LC_ALL, sz);
wprintf(L"—");
tapi bagaimanapun di sini saya melihat (di komputer saya) -
di layar, bukan —
. jadi -—
jika memanggil PrintString(L"—");
(yang dulunya WriteConsoleW
) setelah ini.
jadi satu-satunya cara yang dapat diandalkan untuk mencetak karakter unicode apa pun (didukung oleh windows) - gunakan api WriteConsoleW.
person
RbMm
schedule
14.09.2017
WriteConsoleW
atau terlebih dahulu mengonversi unicode ke multibyte dengan menggunakanWideCharToMultiByte(GetConsoleOutputCP(),..)
untuk digunakan dalam fungsi keluaran A - person RbMm   schedule 14.09.2017printf ("—\n");
dijalankan di output konsol Windows sayaÔÇö
. - person Weather Vane   schedule 14.09.2017WriteConsoleW
denganL"—\n"
. apakah Anda mengerti mengapa ada kesalahan saat Anda menggunakan versi ansi? karena menggunakan halaman kode lain (secara defaultCP_OEMCP
) untuk menerjemahkan string Anda ke unicode (di src Anda,CP_ACP
Anda digunakan) - person RbMm   schedule 14.09.2017_setmode(_fileno(stdout), _O_U16TEXT)
saat program dimulai dan menggunakan I/O C/C++ berkarakter lebar sepertiwprintf
danstd::wcout
. - person Eryk Sun   schedule 15.09.2017GetConsoleOutputCP
). Menurut saya komentar tersebut tidak berarti konsol secara umum tidak mendukung Unicode. Meskipun mengenai yang terakhir, konsol terbatas pada BMP (misalnya kode pengganti ditampilkan sebagai karakter default daripada mendekode pasangan pengganti UTF-16); tidak mendukung penggabungan kode; dan memerlukan font monospace dengan mesin terbang untuk karakternya (penghubung font manual membantu). - person Eryk Sun   schedule 15.09.2017current output codepage
- ini adalah kalimat yang benar-benar salah. keluaran konsol selalu dalam unicode.GetConsoleOutputCP
- ini adalah halaman kode untuk menerjemahkan string multi-byte ke unicode, sebelum menampilkannya - person RbMm   schedule 15.09.2017WriteFile
dipanggil dengan string byte. Di Windows 8+ ini memanggilNtWriteFile
untuk File yang diberikan pada perangkat ConDrv. Konsol terlampir (conhost.exe) menunggu diNtDeviceIoControlFile
, yang dilengkapi dengan permintaan untuk menulis byte tertentu ke buffer layar target. Konsol pertama-tama mendekode byte ini menggunakan halaman kode keluarannya dengan memanggilMultiByteToWideChar
dan sejenisnya. - person Eryk Sun   schedule 15.09.2017GetConsoleOutputCP
, yaitu halaman kode keluaran. Sejauh yang saya tahu, Anda mempermasalahkan nama itu. Tidak ada yang saya katakan salah tentang operasinya. - person Eryk Sun   schedule 15.09.2017WriteConsoleW
- person RbMm   schedule 15.09.2017_setmode(_fileno(stdout), _O_U16TEXT)
lalu gunakan fungsi CRT berkarakter lebar sepertiwprintf
. Ini tidak terlalu efisien karena CRT akhirnya memanggil_putwch_nolock
dalam satu lingkaran pada karakter, dan dengan demikian membuat panggilanWriteConsoleW
untuk setiap karakter. Namun ini adalah konsol I/O interaktif, jadi kami tidak memerlukan kecepatan dan efisiensi ekstrem. - person Eryk Sun   schedule 15.09.2017_setmode(_fileno(stdout), _O_U16TEXT)
wprintf
mulai gunakanWriteConsoleW
(char demi char) sebagai gantinyaWriteFile
. tapi saya pribadi tidak mengerti sama sekali - untuk apa semua masalah ini dengan CRT dan/atau output ansi ketika bisa memanggilWriteConsoleW
dan tidak ada masalah sama sekali - person RbMm   schedule 15.09.2017WriteConsoleW
dan main -printf
dengan cara apa pun menampilkan—
sebagai-
. hanyaWriteConsoleW
yang memberikan tampilan yang benar - person RbMm   schedule 15.09.2017SetConsoleOutputCP(CP_UTF8)
. Opsi kompiler/utf-8
memaksa literal string UTF-8. Saya tidak akan menggunakan ini sebelum Windows 8, dalam hal iniWriteFile
ke konsol salah mengembalikan jumlah karakter yang didekodekan yang ditulis alih-alih jumlah byte yang ditulis. Selain itu,SetConsoleCP(CP_UTF8)
tidak berguna untuk input non-ASCII di semua versi karena konsol membuat asumsi buggy bahwa ia mengkodekan ke ANSI (misalnya 1 byte per karakter) ketika ia mengukur buffer untukWideCharToMultiByte
, yang gagal namunReadFile
'berhasil' dalam membaca nol byte, yaitu EOF. - person Eryk Sun   schedule 15.09.2017CP_UTF8
(65001) sedikit 'ditingkatkan'. Rupanya sebelum pengkodean sekarang mereka hanya mengganti semua karakter non-ASCII dengan Unicode NUL, jadi setidaknya tidak terlihat seperti EOF. Hanya saja semua karakter input non-ASCII berakhir sebagai \x00 di buffer. - person Eryk Sun   schedule 15.09.2017