Ввод и вывод кириллицы в кодировке UTF-8
Написал программу, в которой выводится и вводится кириллица, используя кодировку 1251. Но пришло время перейти на UTF-8, чтоб расширить возможности красивого вывода (таблиц к примеру).
Простая замена кодировки файла и консоли не дала плодов, тогда я начал собирать информацию из разных источников и остановился на таком коде:
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <Windows.h>
void main() {
SetConsoleCP(65001);
SetConsoleOutputCP(65001);
setlocale(LC_ALL, "ru_RU.UTF-8");
wprintf(L"Проверка┏━━┳\n");
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
wchar_t s[32], c;
unsigned long read;
unsigned int i;
for (i = 0; i < 32; i++) {
ReadConsole(handle, &c, 1, &read, NULL);
if (c == '\n' || c == '\r') {
i++;
break;
}
else
s[i] = c;
}
s[i - 1] = L'\0';
wprintf(L"%ls", s);
}
Пришлось использовать и setlocale, и смену кодировки консоли, иначе не работает ввод или выводит не все символы юникода. Но я писал этот код в Visual Studio, а когда для проверки закинул в VSC и CodeBlocks, то обнаружил, что ничего не работает.
Если убрать смену кодировки, то тогда начинает работать ввод, но вывод - нет; если убрать смену локали, то оба метода коммуникации с пользователем перестают работать.
Почему так сильно отличается работа кода в VS и VSC, и как это можно исправить, если кодировка файлов одинаковая?
Ответы (1 шт):
Если уж вы начали писать с использованием WinAPI, то пишите и ввод и вывод с его помощью:
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
int main() {
SetConsoleCP(65001);
SetConsoleOutputCP(65001);
const size_t BUFFER_SIZE = 32;
wchar_t* s = calloc(BUFFER_SIZE, sizeof(wchar_t));
unsigned long read;
HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
if (ReadConsoleW(handle_in, s, BUFFER_SIZE, &read, NULL) == 0) {
printf("Error: %ld", GetLastError());
return -1;
}
if (read > 0) read--; // удаление перевода строки из инпута
unsigned long written;
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsoleW(handle_out, s, read, &written, NULL);
}
Так же, не забывайте освобождать память, закрывать хендлы и обрабатывать ошибки в реальном коде.
P.S. Чтобы консоль могла печатать любые юникодные символы, в ней должен быть установлен соответствующий шрифт. Дефолтный шрифт не всегда удовлетворяет этому требованию.