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 использует только положительные числа, поэтому... почему вы тоже не используете? сохраняя его просто:)