Почему алфавит разделен на несколько диапазонов в этом C-коде?

161

В пользовательской библиотеке я увидел реализацию:

inline int is_upper_alpha(char chValue)
{
    if (((chValue >= 'A') && (chValue <= 'I')) ||
        ((chValue >= 'J') && (chValue <= 'R')) ||
        ((chValue >= 'S') && (chValue <= 'Z')))
        return 1;
    return 0;
}

Это пасхальное яйцо или в чем преимущества стандартного метода Си / Си ++?

inline int is_upper_alpha(char chValue)
{
    return ((chValue >= 'A') && (chValue <= 'Z'));
}
Владимир Ч.
источник
Обратите внимание, что в EBCDIC диапазон символов для букв нижнего регистра стоит перед диапазоном символов для букв верхнего регистра, и оба идут перед цифрами - что в точности противоположно порядку в кодировках на основе ASCII (таких как 8859- серия x, или Unicode, или CP1252, или…).
Джонатан Леффлер
1
Примечание: если 'J' - 'I'и 'S' - 'R'оба равны 1, то я ожидаю, что разумный оптимизатор превратит первое в последнее.
Матье М.

Ответы:

214

Автор этого кода предположительно должен был поддерживать EBCDIC в какой - то точке, где числовые значения букв являются Непоследовательными (пробела существуют между I, Jи R, Sкак вы уже догадались).

Стоит отметить , что C и C ++ стандарты только гарантирует , что символы 0не 9имеют непрерывные числовые значения именно по этой причине, так что ни один из этих методов, строго соответствующий стандартам.

Wintermute
источник
64
Настоящий WTF - это то, почему оригинальный автор не написал комментарий // In the EBCDIC coding, the alphabet has gaps between these values. See URL: xxxx for details. Тогда вам даже не придется задавать вопрос. У вас есть ответ, встроенный в код.
Абеленки
66
@abelenky Если код изначально предназначался для системы, в которой обычно используется ebcdic, он мог казаться очевидным в то время и не нуждался в комментариях, к сожалению, вещи, которые кажутся хорошими в унаследованном коде, сейчас кажутся странными.
Vality
26
@abelenky: Настоящий WTF - это то, почему оригинальный автор не использовал стандартную функциональность, то есть return ( isalpha( chValue ) && isupper( chValue ) )...
DevSolar
4
@ Damon: это не проблема. Возможно, вам придется обрабатывать «чужую» кодировку даже в системе, которая не использует эту кодировку изначально. Таким образом, вы устанавливаете для своей локали заданную кодировку, а затем вы должны держать пальцы скрещенными, чтобы программист фактически использовал стандартные функции вместо выполнения «умного» кодирования, подобного описанному выше, думая, что он знает, что каждая кодировка, с которой когда-либо столкнется его программа ...
DevSolar
6
Если он был написан для поддержки EBCDIC с 1970-х годов, была ли isalpha и isupper даже ANSI или поддерживалась большинством компиляторов тогда?
Никал
54

Похоже, он пытается охватить как EBCDIC, так и ASCII. Ваш альтернативный метод не работает для EBCDIC (у него есть ложные срабатывания, но нет ложных отрицаний)

C и C ++ действительно требуют, '0'-'9'являются смежными.

Обратите внимание , что стандартные библиотечные вызовы действительно знают , запускать ли они на ASCII, EBCDIC или других систем, поэтому они более портативными и , возможно , более эффективным.

MSalters
источник
5
std::isupperфактически запрашивает текущую установленную глобальную локаль C
Линси
1
Да ты прав. Метод написан для покрытия обеих кодировок. Спасибо за ответ!
Владимир Ч.
4
@Lingxi: Да, но это не значит, что вы можете переключить язык с ASCII на EBCDIC. 'A'должен остаться 'A'независимо от локали. ASCII в UTF-8, это было бы возможно.
MSalters
2
@Lingxi: std::isupper запрашивает установленную глобальную локаль C, да, но фаза компиляции, которая интерпретирует символьные литералы, - нет.
Гонки легкости на орбите
1
@Lingxi - Просто быстрое примечание. Сомнительно, std::isupperдействительно ли это необходимо в большинстве случаев. Он учитывает локали, используемые для ввода от пользователя. Но при разборе файлов, взаимодействии с базами данных вы обычно ожидаете какой-то другой язык. Более того, по крайней мере в Linux эти вызовы, связанные с локалью, очень медленные - например, std::isalphaдва раза вызывает dynamic_cast, чтобы «найти» правильную реализацию локали, прежде чем сравнивать один символ.
ibre5041