Char Вопрос о кодировке подписанных/неподписанных
Я прочитал, что C не определяет, подписан ли char или без знака, а на странице GCC говорится, что он может быть подписан на x86 и без знака в PowerPPC и ARM.
Okey, я пишу программу с GLIB, которая определяет char как gchar (не более того, только способ стандартизации).
Мой вопрос: как насчет UTF-8? Он использует больше, чем блок памяти?
Скажем, что у меня есть переменная
unsigned char * string = "Моя строка с UTF8, в которой есть ~ > çã";
См., если я объявляю свою переменную как
без знака
У меня будет только 127 значений (так что моя программа будет хранить больше блоков mem), или UTF-8 тоже изменится на отрицательный?
Извините, если я не могу объяснить это правильно, но я думаю, что я немного сложный.
Примечание:
Спасибо за ответ
Я не понимаю, как это интерпретируется нормально.
Я думаю, что, подобно ascii, если у меня есть подписанная и unsigned char в моей программе, строки имеют разные значения, и это приводит к путанице, представьте себе это в utf8.
Ответы
Ответ 1
У меня было несколько просьб объяснить комментарий, который я сделал.
Тот факт, что тип char
может по умолчанию использовать либо подписанный, либо беззнаковый тип, может быть значительным, когда вы сравниваете символы и ожидаете определенного упорядочения. В частности, UTF8 использует высокий бит (при условии, что char
является 8-битным типом, который истинен на подавляющем большинстве платформ), чтобы указать, что символьная кодовая точка требует представления более одного байта.
Быстрый и грязный пример проблемы:
#include <stdio.h>
int main( void)
{
signed char flag = 0xf0;
unsigned char uflag = 0xf0;
if (flag < (signed char) 'z') {
printf( "flag is smaller than 'z'\n");
}
else {
printf( "flag is larger than 'z'\n");
}
if (uflag < (unsigned char) 'z') {
printf( "uflag is smaller than 'z'\n");
}
else {
printf( "uflag is larger than 'z'\n");
}
return 0;
}
В большинстве проектов, в которых я работаю, мы не используем тип char
, который используется без ограничений, используя typedef, который явно указывает unsigned char
. Что-то вроде uint8_t
от stdint.h
или
typedef unsigned char u8;
Как правило, работа с типом unsigned char
работает хорошо и имеет мало проблем - в той области, в которой я наблюдал случайные проблемы, является использование чего-то такого типа для управления циклом:
while (uchar_var-- >= 0) {
// infinite loop...
}
Ответ 2
Использование unsigned char имеет свои плюсы и минусы. Наибольшие преимущества заключаются в том, что вы не получаете расширения знака или других смешных функций, таких как подписанное переполнение, что приведет к неожиданным результатам вычислений. Unsigned char также совместим с <cctype> макросы/функции, такие как isalpha (ch) (все это требует значений в unsigned char). С другой стороны, для всех функций ввода/вывода требуется char *, что требует от вас выполнения при каждом вводе/выводе.
Что касается UTF-8, то хранить его в подписанных или неподписанных массивах отлично, но вы должны быть осторожны с этими строковыми литералами, так как нет никакой гарантии, что они будут действительными UTF-8. С++ 0x добавляет строковые литералы UTF-8, чтобы избежать возможных проблем, и я бы ожидал, что следующий стандарт C также примет их.
В общем, все должно быть хорошо, если вы убедитесь, что файлы исходного кода всегда закодированы в кодировке UTF-8.
Ответ 3
Две вещи:
-
Подписывается ли тип char или unsigned не влияет на вашу способность транслировать строки с кодировкой UTF8 в и из любого используемого типа строки отображения (WCHAR или whatnot). Не беспокойтесь об этом, другими словами: байты UTF8 - это просто байты, и все, что вы используете в качестве кодировщика/декодера, будет делать правильно.
-
Некоторые из ваших замешательств могут заключаться в том, что вы пытаетесь это сделать:
unsigned char *string = "This is a UTF8 string";
Не делайте этого - вы смешиваете разные понятия. Закодированная строка UTF-8 представляет собой всего лишь последовательность байтов. Строковые литералы C (как указано выше) на самом деле не предназначены для представления этого; они предназначены для представления строк, закодированных в ASCII. Хотя в некоторых случаях (например, здесь) они оказываются одними и теми же, в вашем примере в вопросе они могут этого не делать. И конечно же в других случаях их не будет. Загрузите строки Unicode из внешнего ресурса. В общем, я опасаюсь встраивать не-ASCII-символы в исходный файл .c; даже если компилятор знает, что с ними делать, другое программное обеспечение в вашей toolchain не может.
Ответ 4
signed/unsigned влияет только на арифметические операции. если char не имеет знака, то более высокие значения будут положительными. в случае их подписания они будут отрицательными. Но диапазон все тот же.
Ответ 5
Не совсем, unsigned
/signed
не определяет, сколько значений может удерживать переменная. Он определяет, как они интерпретируются.
Итак, unsigned char
имеет такое же количество значений, что и signed char
, за исключением того, что у одного есть отрицательные числа, а у другого нет. Он все еще 8 бит (если мы предположим, что a char
содержит 8 бит, я не уверен, что он везде).
Ответ 6
При использовании char * в качестве строки не возникает различий. Единственный раз, когда подписанный /unsigned будет иметь значение, - это если вы будете интерпретировать его как число, например, для арифметики или если вы должны печатать его как целое число.
Ответ 7
UTF-8 символы нельзя считать сохраненными в одном байте. Символы UTF-8 могут иметь ширину 1-4 байта. Таким образом, char
, wchar_t
, signed
или unsigned
не будет достаточным для того, чтобы предположить, что одна единица всегда может хранить один символ UTF-8.
В большинстве платформ (например, PHP,.NET и т.д.) вы обычно создаете строки (например, char[]
в C), и вы используете библиотеку для преобразования кодировок и синтаксических символов из строки.
Ответ 8
Что касается тебя, вопрос:
Думаю, если у меня есть пение или неподписанное ARRAY символов, это может привести к неправильной работе моей программы? - drigoSkalWalker
Да. Моя сделала. Heres - простая исполняемая выдержка из моего приложения, которая совершенно ошибочна, если использовать обычные подписанные символы.
Попробуйте запустить его после изменения всех символов в unsigned в параметрах. Вот так:
int is_valid ( unsigned char c);
он должен работать правильно.
#include <stdio.h>
int is_valid(char c);
int main() {
char ch = 0xFE;
int ans = is_valid(ch);
printf("%d", ans);
}
int is_valid(char c) {
if((c == 0xFF) || (c == 0xFE)) {
printf("NOT valid\n");
return 0;
}
else {
printf("valid\n")
return 1;
}
}
Что он делает, это проверить, является ли char допустимым байтом внутри utf-8.
0xFF и 0xFE НЕ являются допустимыми байтами в utf-8.
Представьте себе проблему, если функция проверяет ее как действительный байт?
что происходит:
0xFE
=
11111110
=
254
Если вы сохраните это в обычном char (который подписан), самый левый бит, самый старший бит, делает его отрицательным. Но какое это отрицательное число?
Он делает это, переворачивая бит и добавляя один бит.
11111110
00000001
00000001 + 00000001 =
00000010 = 2
и помните, что он сделал его отрицательным, поэтому он становится -2
so (-2 == 0xFE) в функции of theourse не является истиной.
то же самое для (-2 == 0xFF).
Таким образом, функция, которая проверяет недопустимые байты, завершает проверку недопустимых байтов, как будто они в порядке: -o.
Две другие причины, по которым я могу думать о том, чтобы придерживаться unsigned при работе с utf-8:
-
Если вам может потребоваться некоторое смещение вправо справа, могут возникнуть проблемы, потому что тогда вы можете добавить 1 слева, если используете подписанные символы.
-
utf-8 и unicode использует только положительные числа, поэтому... почему вы тоже не используете? сохраняя его просто:)