Представление кодов ASCII в char на платформах, не являющихся дополнением к двум - PullRequest
0 голосов
/ 03 ноября 2019

На основных платформах все просто: буква 'A' имеет ASCII-код 65, поэтому (char)65, (unsigned char)65, (signed char)65, что приводит к одной и той же битовой последовательности в памяти.

Но, как я знаю, стандарт C не требует кодирования чисел со знаком с использованием какой-либо конкретной схемы. Таким образом, возможно, что на некоторых машинах (signed char)65 и (unsigned char)65 представлены с помощью разных битовых последовательностей. (пример: https://en.wikipedia.org/wiki/Offset_binary) Прав ли я или такое поведение запрещено где-то в стандарте?

Если это возможно: какой из них будет 'A' (например, в каком-то универсальном текстовом файле)редактор)? Это как-то связано с подписью простого char типа?

Есть ли вообще переносимый способ обработки таких случаев?

Другая сторона той же проблемы.

Пример У меня есть char some_text[100];, и я хочу прочитать его как неподписанные коды. Есть два варианта:

(unsigned char)(some_text[i]) = преобразует значение со знаком в беззнаковое, сохраняя его числовое значение, когда это возможно

*(unsigned char*)(some_text+i) = сохранит последовательность битов, но значение может быть изменено в зависимости от платформы

Какой из них будет более портативным и правильным, если подумать о таких экзотических платформах, описанных выше?

Ответы [ 2 ]

2 голосов
/ 04 ноября 2019

ASCII-коды - это числа от 0 до 127.

Стандарт C требует, чтобы представление этих чисел было одинаковым для типов знаков со знаком и без знака.

Значения хранятся в беззнаковыхбитовые поля и объекты типа unsigned char должны быть представлены в чистом двоичном формате

и

signed char не должны иметь никаких битов заполнения. Должен быть ровно один знаковый бит. Каждый бит, который является битом значения, должен иметь то же значение, что и тот же бит в представлении объекта соответствующего беззнакового типа

. Эти положения позволяют безопасно преобразовывать типы со знаком и без знака char,и (что более важно) между их массивами. Эти преобразования ведут себя предсказуемо и переносимо. Если доступ к объекту типа signed char осуществляется через значение unsigned char l, и значение исходного объекта неотрицательно (все коды ASCII), гарантированное значение будет таким же, что и исходное значение. И наоборот, если доступ к unsigned char осуществляется через значение signed char l, а исходное значение соответствует диапазону со знаком (все коды ASCII делают), оно гарантированно не изменится. Это важно, потому что различные API часто используют массивы символов неудобной подписи;мы хотим быть уверены, что можем использовать такие API с простым приведением к нашему предпочтительному типу символа.

А как насчет отрицательных значений? Это не ASCII, но мы часто работаем с другими наборами символов и кодировками (например, UTF-8), и они могут иметь отрицательные члены.

Отрицательные значения могут быть представлены точно одним из трех методов.

Если бит знака равен единице, значение должно быть изменено одним из следующих способов:

соответствующее значение со знаком бит 0 обнуляется (знак и величина);
знакбит имеет значение - (2M) (дополнение к двум);
знаковый бит имеет значение - (2M-1) (дополнение к одному).

Здесь мы имеем проблему с отрицательным нулем в представлении знака и величины. Он не может выжить в оба конца через неподписанный тип. Отсюда следует, что некоторые реализации, такие как UTF-8, не могут быть легко поддержаны такой реализацией. Это не проблема для ASCII.

Что касается других целочисленных типов, представление здесь не очень важно. Когда вы используете, например, int для представления значения ASCII, вы обычно интересуетесь значением, а не представлением. Вы можете безопасно преобразовать значения от 0 до 127 между всеми целочисленными типами, поддерживаемыми C. (Другие целочисленные типы могут иметь биты заполнения, но в остальном большинство вышеприведенного также верно и для них; это не имеет значения, поскольку нормальное программирование почти никогда не затрагивается).

Экзотическая платформа, которая использует другое представление символов, не может поддерживать стандарт C, поэтому писать переносимо для таких платформ не имеет смысла.

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

1 голос
/ 03 ноября 2019

Прежде всего, char сам имеет подпись, определяемую реализацией, поэтому он может быть подписанным или неподписанным, в зависимости от компилятора.

Значение любого 7-битного символа символа, приведенного к знаку илибез знака всегда будет положительным значением. Говоря об ASCII, мы имеем в виду только исходную 7-битную таблицу. Это никогда не может иметь отрицательное значение. Следовательно, лежащее в основе представление подписи не имеет значения, потому что значение символа никогда не может быть отрицательным, если оно не превышает 7 бит.

Подводя итог вашим вопросам:

Итаквозможно, что на некотором компьютере (знаковый символ) 65 и (неподписанный символ) 65 представлены различными битовыми последовательностями.

Нет.

Прав ли я или этоповедение запрещено где-то в стандарте?

Да, C17 6.3.1.3. «Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _Bool, если значение может быть представлено новым типом, оно не изменяется.»

Единственный код, который столкнется с проблемами переносимости, - это использование кодав таблицах символов длиной 8 или более бит. Но тогда вместо этого обычно используется wchar_t.

...