Кириллические символы [с использованием utf-8
] являются многобайтовыми char
s. Ваш "символ" в шестнадцатеричном формате - это строка/массив:
D0B1
Таким образом, вы не можете использовать %c
для его получения. Вам нужно использовать %s
:
#include <stdio.h>
int
main(void)
{
char utf[1000];
char *cp;
scanf("%s", utf);
printf("%s\n", utf);
for (cp = utf; *cp != 0; ++cp)
printf(" %2.2X",*cp & 0xFF);
printf("\n");
return 0;
}
Вот результат:
б
D0 B1
ОБНОВЛЕНИЕ:
Итак, как этот char расположен в памяти? Может ли C сделать char 2-байтовым, когда дело доходит до кириллицы?
Прежде всего, см.: https://en.wikipedia.org/wiki/UTF-8< /а>
Когда вы вводите кириллический символ с помощью клавиатуры, это комбинация вашей клавиатуры, программы-эмулятора терминала и текстового редактора, которая преобразует последовательность клавиатуры в последовательность utf-8
, которая заканчивается в редактируемом текстовом файле.
То, что вы называете кириллическим символом, utf-8
называет "кодовой точкой".
При помещении в текстовый файл кодовая точка становится многобайтовой последовательностью, как упоминалось выше.
scanf
и printf
ничего об этом не знают. Например, printf
просто отправляет строку: XXXXXXX\0
, где X может быть одиночным символом ASCII или частью многосимвольного кода.
Эмулятор терминала должен понять это и вывести правильный символ из набора шрифтов utf-8 [который содержит символы кириллицы, греческие символы, французские символы и т. д.]
Такие функции, как strlen
и strcpy
, только заботятся о завершающем символе 0x00 EOS. Таким образом, технически они работают и обычно могут передавать строку utf-8
так же легко, как и строку ASCII, поскольку EOS не зависит от этого.
Но strlen
даст вам число char
в строке. Например, в приведенном выше примере strlen
вернет 2, потому что D0
и B1
считаются отдельными значениями char
в массиве char
.
И strchr
[вероятно] не сработает. Вы, вероятно, захотите использовать strstr
вместо utf-8
.
Конечно, в нем есть только одна кодовая точка для кириллического символа, поэтому utf-8
функциям приходится обрабатывать массив по-разному. Например, при подсчете количества кодовых точек они должны видеть, что D0B1
— это одиночная кодовая точка, поэтому в результате получается один
Общее правило состоит в том, что ASCII (0x01-0x7F
) отображается непосредственно на utf-8
как отдельные char
s. Все, что имеет установленный старший бит (0x80
), является частью многобайтовой кодовой точки utf-8
. 0x40
используется для обозначения начального [крайнего левого] байта последовательности. Все остальные байты в последовательности имеют вид (в битах): 10xxxxxx
. Количество оставшихся байтов в последовательности обозначается количеством бит префикса 1 в начальном байте. В таблице ниже показано, как декодировать последовательность байтов (x
обозначает бит, являющийся частью значения кодовой точки):
# of Start Remaining Bytes
bytes Byte
1 0xxxxxxx
2 110xxxxx 10xxxxxx
3 1110xxxx 10xxxxxx 10xxxxxx
4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
Таким образом, функция, поддерживающая utf-8
, может обнаруживать и пропускать кодовые точки при сканировании в прямом или обратном направлении. И может различать две [или более] смежные многобайтовые кодовые точки.
person
Craig Estey
schedule
05.12.2018
char
может хранить минимум один байт. - person klutt   schedule 06.12.2018char
- это тип, способный представлять символ из базового набора символов реализации. - person EOF   schedule 06.12.2018char
не хранит ничего. Объект что-то хранит, поэтому правильнее было бы сказать, что байт может хранить ровно одноchar
. - person EOF   schedule 06.12.2018CHAR_BIT
определяется реализацией и должно быть равно или больше 8. - person EOF   schedule 06.12.2018char
в значительной степени является определением байта, каким бы большим он ни был. Вы двое смешиваете два определения: байт = октет (что обычно подразумевается в настоящее время в сообществе разработчиков программного обеспечения) и байт = минимальное адресуемое количество =char
(что означают стандарты C и C++ для байта). - person Matteo Italia   schedule 06.12.2018