【发布时间】:2010-08-04 06:11:20
【问题描述】:
我想知道“isupper”宏是如何在 C/C++ 中定义的。能否请您提供相同的信息或指向我可用的资源。我尝试查看 ctype.h 但无法弄清楚。
【问题讨论】:
标签: c++ c macros definition
我想知道“isupper”宏是如何在 C/C++ 中定义的。能否请您提供相同的信息或指向我可用的资源。我尝试查看 ctype.h 但无法弄清楚。
【问题讨论】:
标签: c++ c macros definition
它是由实现定义的——每个供应商都可以而且通常会以不同的方式来做。
最常见的通常涉及“特征”表 - 每个字符都有一个元素的数组,该元素的值是标志的集合,表示有关字符的详细信息。一个例子是:
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')
【讨论】:
#define isdigit(x) ((unsigned)(x)-'0'<10),因为ISO C要求行为与这个表达式相同并且它是最优的。
isupper 而不是iswupper。在 UTF-8 中,ASCII 范围之外的所有字节本身没有意义,仅作为多字节序列的一部分,因此非宽 is* 函数对于非 ASCII 字节总是返回 0。
这是一个函数,而不是宏。 isupper() 的函数定义因语言环境和当前字符集等因素而异 - 这就是为什么有专门用于此目的的函数。
对于 ASCII,由于字母的分配方式,实际上很容易对此进行测试。如果字符的 ASCII 码介于 0x41 和 0x5A 之间,则为大写字母。
【讨论】:
它实际上相当复杂,例如在 GCC 中。但是 isupper 的一个简单实现可以(尽管它有一个双重评估错误)最简单地定义为:
#define isupper(c) (c >= 'A') & (c
GCC 专门检查当前语言环境的字符中的位 0 是否为 1:
(*__ctype_b_loc ())[(int) (c)] & (unsigned short int) (1
其中 __ctype_b_loc() 是一个函数,它返回指向当前语言环境中的字符数组的指针,其中包含当前字符集中每个字符的特征。
【讨论】:
isupper(*s++)...)。您需要转换为 unsigned 并使用无符号溢出语义来测试范围,而无需多次评估参数。