Семантика сравнения объектов типа char - PullRequest
8 голосов
/ 19 декабря 2010

Когда я читал какой-то старый код сегодня, я заметил следующую строку assert:

assert(('0' <= hexChar && hexChar <= '9')
    || ('A' <= hexChar && hexChar <= 'F')
    || ('a' <= hexChar && hexChar <= 'f'));

Цель состоит в том, чтобы утверждать, что hexChar является шестнадцатеричной цифрой ([0-9A-Fa-f]). Он делает это, полагаясь на ASCII-подобный порядок char объектов, представляющих 'A', 'B', ..., 'F' и 'a', 'b', ..., 'f'.

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

Стандарт C ++ в Разделе 2.3, Наборы символов, упоминает:

Базовый набор символов и базовый набор широких символов должны содержать все элементы базового набора исходных символов, а также управляющие символы, представляющие предупреждение, возврат и возврат каретки плюс нулевой символ (соответственно нулевой широкий символ ), представление которого имеет все нулевые биты. Для каждого базового набора символов выполнения значения элементов должны быть неотрицательными и отличными друг от друга. В исходных и исполняющих базовых наборах символов значение каждого символа после 0 в приведенном выше списке десятичных цифр должно быть на единицу больше, чем значение предыдущего. Набор символов выполнения и набор широких символов исполнения являются определяемыми реализацией надмножествами базового набора символов выполнения и базового набора широких символов выполнения, соответственно. Значения членов наборов символов выполнения и наборов дополнительных элементов зависят от локали.

Я понимаю, что ('0' <= hexChar && hexChar <= '9') в порядке, потому что '0', '1', ..., '9' - цифры, и каждая из них имеет значение на единицу больше, чем предыдущее. Однако порядок других основных исходных символов по отношению друг к другу все еще определяется реализацией.

Это правильное утверждение? Ничего не зная о компиляторе C ++ (не зная деталей реализации), нужно ли переписать assert следующим образом?

assert(('0' <= hexChar && hexChar <= '9')
    || ('A' == hexChar || 'B' == hexChar || 'C' == hexChar || 'D' == hexChar || 'E' == hexChar || 'F' == hexChar)
    || ('a' == hexChar || 'b' == hexChar || 'c' == hexChar || 'd' == hexChar || 'e' == hexChar || 'f' == hexChar));

Ответы [ 3 ]

7 голосов
/ 19 декабря 2010

Первая строка, сравнение со значениями '0' и '9', является переносимой на 100%. Язык C гарантирует одинаковое поведение для всех реализаций.

Вторая и третья строки в принципе определяются реализацией, но никогда не было и не будет реализации, где их поведение отличается. Единственная несовместимая с ISO646 кодировка символов, которая когда-либо использовалась с языком C (и единственная причина, по которой C допускает несовместимые с ISO646 кодировки), - это EBCDIC, которая размещает буквы от 'A' до 'F' именно там, где они должны попадают в шестнадцатеричные значения (в общем случае буквы в EBCDIC несмежны, но AF - это одна смежная группа).

С учетом вышесказанного, если вам не нужно поддерживать унаследованные мэйнфреймы, нет смысла пытаться обрабатывать базовую кодировку символов "переносимо" в C. char равно 8 битам, значения 0-127 являются ASCII, а значения 128-255 являются частью многобайтовой кодировки символов, зависящей от локали или данных, которую мы когда-нибудь сможем предположить как UTF-8.

5 голосов
/ 19 декабря 2010

На ваш первый вопрос: да.

На ваш второй вопрос: возможно, но, вероятно, вам следует рассмотреть возможность использования функции библиотеки C isxdigit или ее варианта на языке C ++.

3 голосов
/ 19 декабря 2010

Технически для компилятора C ++ вполне допустимо использовать какую-либо другую кодировку символов.Однако реальность такова, что вы почти наверняка не найдете платформу, где этот код не работает.Это особенно верно, поскольку новые доминирующие кодировки символов основаны на Unicode, как UTF-16, и Unicode разделяет все значения ASCII для всех символов в наборе ASCII.Единственная причина, по которой это определяется реализацией - это очень, очень старые унаследованные платформы, которые еще существовали, когда была написана эта часть Стандарта, и вам пришлось бы существенно реорганизовать свой код для запуска на любой платформе, отличной от ASCII.

...