Русская строка в C

251
06 июня 2017, 00:30

Как получается что русские символы умещаются в C строке в кодировке UTF-8 когда каждый русский символ в этой кодировке занимает 2 байта, а ячейка в C строке вмещает только 1 байт? Почему если выводить эту строку, то она выведется без проблем, а если выводить её посимвольно, то она выводит ошибки? Ещё если можно, то посоветуйте материалов почитать по этой теме.

char a[] = "Строка";
std::cout << a << std::endl;
for (int i = 0; i < 6; i++)
std::cout << a[i] << std::endl;

Answer 1

Чудес не бывает - символы, занимающие больше одного байта в Си так же занимают больше одного байта. В случае со строкой char они лежат в нескольких ячейках (в случае с двухбайтными - первый символ лежит в первых двух, второй - во вторых двух).

Если говорить о C++, то для многобайтных символов есть специальный тип wchar_t, который имеет размер в 4 байта для GNU/Linux и 2 байта для Windows API

Аналогом std::string для этого типа является std::wstring.

http://en.cppreference.com/w/cpp/string/basic_string

// сперва считаем символ беззнаковым, потом переводим его в целое число
char a[] = "Строка";
std::cout << (int)(unsigned char)a[0] << "; " << (int)(unsigned char)a[1] << std::endl;

Выведет 208; 161 (https://ideone.com/FyUdhj)

Согласно вот это (https://unicode-table.com/ru/0421/) таблице, символ С в UTF-8 представляется двумя байтами, как раз 208 161

Answer 2

Ячейка в С-строке вмещает, конечно, один байт, но каждый символ в таком случае будет занимать в ней два места. И длина всей строки -- 12

char a[] = "Строка";
std::cout << a << ' ' << strlen(a) << std::endl; // Строка 12

Например, если вывести из этой строки по два символа, то выведутся правильные символы:

for (int i = 0; i < 6; i++)
    std::cout << a[2*i] << a[2*i+1] << std::endl;

utf-8 -- мультибайтовая кодировка (разные символы могут занимать разное количество байт). В том числе кириллические символы будут занимать два байта. При инициализации строки каждый по два байта и займёт.
Следующие две конструкции с точки зрения языка эквивалентны:

char a[] = "\xd0\xa1\xd1\x82\xd1\x80\xd0\xbe\xd0\xba\xd0\xb0";
char a[] = "Строка";
READ ALSO
Взятие объекта по адресу в конструторе копирования

Взятие объекта по адресу в конструторе копирования

Всем добрый деньСтандартный конструктор копирования в классе выглядит так: SomeClass(const SomeClass &obj) Как я понимаю, const отвечают за то, что в процессе...

260
Оператор присваивания и swap

Оператор присваивания и swap

Добрый деньЕсть такая реализация Оператора присваивания

243
Вывод по ключу в порядке убывания.

Вывод по ключу в порядке убывания.

Есть простая хеш-функция key%m; Массив из m=20 элементов Есть 100 объектов, с рандомными ключамиМассив представляет собой массив стеков

299
Плагин MMENU jquery

Плагин MMENU jquery

При нажатие на меню, страницу скроллит вверх и только после этого открывается меню на фотке скрипт включения, в библиотеке ничего не менял,...

345