Char C вопрос о кодировке подписан / не подписан - PullRequest
10 голосов
/ 26 марта 2010

Я читал, что C не определяет, является ли символ подписанным или неподписанным, и на странице GCC это говорит о том, что он может быть подписан на x86 и неподписан в PowerPPC и ARM.

Окей, я пишу программу с GLIB, которая определяет char как gchar (не более того, только способ стандартизации).

Мой вопрос, а как насчет UTF-8? Это использовать больше, чем блок памяти?

Скажи, что у меня есть переменная

unsigned char * string = "Моя строка с кодом UTF8 ~> çã";

Смотрите, если я объявлю свою переменную как

без знака

У меня будет только 127 значений (так что моя программа будет хранить больше блоков памяти) или UTF-8 тоже изменится на отрицательный?

Извините, если я не могу объяснить это правильно, но я думаю, что я немного сложен.

Примечание: Спасибо за весь ответ

Я не понимаю, как это обычно интерпретируется.

Я думаю, что, подобно ascii, если в моей программе есть подписанный и неподписанный символ, строки имеют разные значения, и это приводит к путанице, представьте это в utf8, так.

Ответы [ 8 ]

6 голосов
/ 26 марта 2010

У меня было несколько просьб объяснить мой комментарий.

Тот факт, что тип 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...
}
5 голосов
/ 26 марта 2010

Использование неподписанного символа имеет свои плюсы и минусы. Самым большим преимуществом является то, что вы не получите расширение знака или другие забавные функции, такие как переполнение со знаком, которое приведет к неожиданным результатам вычислений. Беззнаковый символ также совместим с макросами / функциями, такими как isalpha (ch) (все это требует значений в диапазоне без знака). С другой стороны, все функции ввода / вывода требуют char *, требуя, чтобы вы выполняли приведение при каждом вводе / выводе.

Что касается UTF-8, хранить его в массивах со знаком или без знака хорошо, но вы должны быть осторожны с этими строковыми литералами, так как нет никакой гарантии, что они являются действительными UTF-8. C ++ 0x добавляет строковые литералы UTF-8, чтобы избежать возможных проблем, и я ожидаю, что следующий стандарт C также примет их.

В целом, с вами все должно быть в порядке, если вы уверены, что ваши файлы исходного кода всегда в кодировке UTF-8.

4 голосов
/ 26 марта 2010

Две вещи:

  1. Независимо от того, является ли тип символа подписанным или неподписанным, это не повлияет на вашу способность переводить строки в кодировке UTF8 и из любого типа отображаемой строки (WCHAR или еще много чего). Не беспокойтесь об этом, другими словами: байты UTF8 - это просто байты, и все, что вы используете в качестве кодера / декодера, будет работать правильно.

  2. Некоторые из ваших заблуждений могут быть из-за того, что вы пытаетесь сделать это:

    unsigned char *string = "This is a UTF8 string";
    

    Не делай этого - ты смешиваешь разные понятия. Строка в кодировке UTF-8 - это просто последовательность байтов. Строковые литералы C (как указано выше) не были предназначены для представления этого; они предназначены для представления строк в кодировке ASCII. Хотя в некоторых случаях (например, у меня здесь) они оказываются одним и тем же, но в вашем примере в вопросе они могут не совпадать. И, конечно, в других случаях они не будут. Загрузите строки Unicode из внешнего ресурса. В общем, я бы с осторожностью вставлял не-ASCII символы в исходный файл .c; даже если компилятор знает, что с ними делать, другие программы в вашем наборе инструментов могут этого не делать.

2 голосов
/ 26 марта 2010

подписанный / неподписанный влияет только на арифметические операции. если char без знака, то более высокие значения будут положительными. в случае подписи они будут отрицательными. Но диапазон все тот же.

1 голос
/ 26 марта 2010

Не имеет значения при использовании символа * в качестве строки. Единственный раз, когда подписанный / неподписанный будет иметь значение, если вы будете интерпретировать его как число, как для арифметики, или если вы должны были напечатать его как целое число.

1 голос
/ 26 марта 2010

Не совсем, unsigned / signed не определяет, сколько значений может содержать переменная. Он определяет, как они интерпретируются .

Итак, unsigned char имеет то же количество значений, что и signed char, за исключением того, что у одного есть отрицательные числа, а у другого - нет. Это все еще 8 бит (если мы предположим, что char содержит 8 бит, я не уверен, что это везде).

0 голосов
/ 06 октября 2017

На ваш вопрос:

Подумайте, если у меня есть неподписанный или неподписанный массив символов, может ли это заставить мою программу работать неправильно? - drigoSkalWalker

Да. Мой сделал. Вот простая исполняемая выдержка из моего приложения, которая совершенно неверна при использовании обычных подписанных символов. Попробуйте запустить его после изменения всех символов без знака в параметрах. Как это:

int is_valid ( без знака 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;
    }
}  

То, что он делает, проверяется, если символ является действительным байтом в utf-8. 0xFF и 0xFE НЕ являются действительными байтами в utf-8. представьте себе проблему, если функция проверяет его как действительный байт?

что происходит так:

0xFE
= 
11111110 
= 
254

Если вы сохраните это в обычном символе (который подписан), то самый левый, самый значимый бит делает его отрицательным. Но что это за отрицательное число?

Это делается путем переключения битов и добавления одного бита.

11111110
00000001
00000001 + 00000001 =
00000010 = 2

и помните, что оно стало отрицательным, поэтому оно становится -2

так (-2 == 0xFE) в функции конечно не верно. То же самое касается (-2 == 0xFF).

Таким образом, функция, которая проверяет наличие недопустимых байтов, завершает проверку недопустимых байтов, как будто они в порядке: -o.

Две другие причины, по которым я могу придерживаться unsigned при работе с utf-8:

  1. Если вам может понадобиться сдвиг битов вправо, могут возникнуть проблемы, потому что тогда вы можете добавить 1 слева, если используете подписанные символы.

  2. utf-8 и unicode используют только положительные числа, так что ... почему вы тоже? сохраняя это простым:)

0 голосов
/ 26 марта 2010

UTF-8 символов нельзя хранить в одном байте. Символы UTF-8 могут иметь ширину 1-4 байта. Таким образом, char, wchar_t, signed или unsigned будет недостаточно для предположения, что одна единица всегда может хранить один символ UTF-8.

На большинстве платформ (таких как PHP, .NET и т. Д.) Вы обычно строите строки (например, char[] в C), и вы используете библиотеку для преобразования между кодировками и анализа символов из строки.

...