Я хочу знать, как макрос isupper определен в C / C ++. Не могли бы вы предоставить мне то же самое или указать мне доступные ресурсы. Я попытался посмотреть ctype.h, но не понял.
4 ответа
Его реализация определена - каждый поставщик может и обычно делает это по-своему.
Чаще всего используется таблица «признаков» - массив с одним элементом для каждого символа, значение которого представляет собой набор флагов, указывающих подробности о персонаже. Примером может быть:
traits[(int) 'C'] = ALPHA | UPPER | PRINTABLE;
В этом случае isupper () будет выглядеть примерно так:
#define isupper(c) ((traits[(int)(c)] & UPPER) == UPPER)
Это зависит от реализации. Один из очевидных способов реализовать это:
extern char *__isupper;
#define isupper(x) ((int)__isupper[(x)])
Где __isupper
указывает на массив из 0 и 1, определяемый локалью. Однако этот вид техники потерял популярность, поскольку доступ к глобальным переменным в разделяемых библиотеках довольно неэффективен и создает постоянные требования к ABI, а также поскольку он несовместим с локальными локальными стандартами потока POSIX.
Другой очевидный способ реализовать его в реализациях только для ASCII или UTF-8:
#define isupper(x) ((unsigned)(x)-'A'<='Z'-'A')
Это функция, а не макрос. Определение функции isupper()
различается в зависимости от таких вещей, как локаль и текущий набор символов - поэтому существует функция специально для этой цели.
Для ASCII, из-за способа присвоения букв, на самом деле довольно легко проверить это. Если код ASCII символа находится между 0x41
и 0x5A
включительно, то это заглавная буква.
На самом деле это довольно сложно, например, в GCC. Но простая реализация isupper может быть (хотя и имеет ошибку двойной оценки) проще всего определить как:
# определить isupper (c) (c> = 'A') & (c <= 'Z')
GCC специально проверяет, что бит 0 равен 1 в символе для текущей локали:
(* __ ctype_b_loc ()) [(int) (c)] & (unsigned short int) (1 << (0))
Где __ctype_b_loc () - это функция, которая возвращает указатель на массив символов в текущей локали, который содержит характеристики для каждого символа в текущем наборе символов.
isupper(*s++)
...). Вам нужно привести к unsigned
и использовать семантику беззнакового переполнения, чтобы проверить диапазон, не оценивая аргумент более одного раза.
Похожие вопросы
Связанные вопросы
Новые вопросы
c++
C++ — это язык программирования общего назначения. Изначально он разрабатывался как расширение C и имел аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде, который будет скомпилирован с помощью компилятора C++. Используйте тег версии для вопросов, связанных с конкретной стандартной версией [C++11], [C++14], [C++17], [C++20] или [C++23]. и т.д.
#define isdigit(x) ((unsigned)(x)-'0'<10)
, потому что ISO C требует, чтобы поведение было идентично этому выражению и было оптимальным.isupper
неiswupper
. В UTF-8 все байты вне диапазона ASCII не имеют значения сами по себе, только как часть многобайтовых последовательностей, поэтому неширокие функцииis*
всегда возвращают 0 для байтов, отличных от ASCII.