我想了解以下代码:
//...
#define _C 0x20
extern const char *_ctype_;
//...
__only_inline int iscntrl(int _c)
{
return (_c == -1 ? 0 : ((_ctype_ + 1)[(unsigned char)_c] & _C));
}它起源于来自obenbsd操作系统源代码的文件ctype.h。此函数检查字符是控制字符还是ascii范围内的可打印字母。这是我目前的思维链:
奇怪的是,每次返回0时,给定的字符_c都不是可打印的字符。否则,当它可打印时,函数只返回一个不感兴趣的整数值。我的理解问题在步骤3,4(有点)和5中。
谢谢你的帮助。
发布于 2019-11-15 15:24:49
_ctype_似乎是符号表的一个受限的内部版本,我猜+ 1是因为它的索引0是不可打印的,所以他们并没有费心保存它的索引0。或者,他们使用的是一个1索引表,而不是C中自定义的0索引表。
C标准为所有ctype.h .h函数规定了这一点:
在所有情况下,参数都是
int,其值应表示为unsigned char或等于宏EOF的值。
一步一步地遍历代码:
int iscntrl(int _c) int类型实际上是字符,但是处理EOF需要所有ctype.h函数,所以它们必须是int。-1的检查是针对EOF的检查,因为它有值-1。_ctype+1是用于获取数组项的地址的指针算法。[(unsigned char)_c]只是对该数组的数组访问,其中强制转换是强制执行参数可表示为unsigned char的标准要求。请注意,char实际上可以保持负值,因此这是防御性编程。[]数组访问的结果是来自其内部符号表的单个字符。&掩码是为了从符号表中获取特定的一组字符。显然,所有5位设置(掩码0x20)的字符都是控制字符。如果不看桌子,这是没有意义的。发布于 2019-11-15 15:19:21
_ctype_是指向257个字节的全局数组的指针。我不知道_ctype_[0]是用来做什么的。_ctype_[1]通过_ctype_[256]_表示字符0,…的字符类别分别:_ctype_[c + 1]表示字符c的类别。这与_ctype_ + 1指向一个由256个字符组成的数组相同,其中(_ctype_ + 1)[c]表示字符c的类别。
(_ctype_ + 1)[(unsigned char)_c]不是一个声明。它是一个使用数组下标运算符的表达式。它正在访问从(unsigned char)_c开始的数组的位置(_ctype_ + 1)。
代码将_c从int转换为unsigned char并不是绝对必要的: ctype函数将char值转换为unsigned char (char在OpenBSD上签名):正确的调用是char c; … iscntrl((unsigned char)c)。它们的优点是确保不存在缓冲区溢出:如果应用程序调用iscntrl的值超出了unsigned char的范围而不是-1,则此函数返回的值可能没有意义,但至少不会导致崩溃或位于数组边界外地址的私有数据泄漏。如果函数被调用为char c; … iscntrl(c),则该值甚至是正确的,只要c不是-1。
使用-1特例的原因是它是EOF。许多在char上操作的标准C函数(例如,getchar )将字符表示为一个int值,该值是包装到一个正范围的字符值,并使用特殊值EOF == -1表示不能读取字符。对于像getchar这样的函数,EOF表示文件的结尾,因此名为getchar艾瑞克·波斯皮奇尔建议代码最初只是return _ctype_[_c + 1],这可能是正确的:_ctype_[0]将是EOF的值。如果函数被误用,这种更简单的实现会产生缓冲区溢出,而当前的实现避免了上面讨论的这种情况。
如果v是数组中的值,则v & _C将测试0x20处的位是否在v中设置。数组中的值是字符所在类别的掩码:_C设置为控制字符,_U设置为大写字母,等等。
发布于 2019-11-15 15:40:34
我将从第三步开始:
将未定义指针指向的增量增加1。
指针是,而不是未定义的。它只是在其他编译单元中定义的。这就是extern部件告诉编译器的内容。因此,当所有文件链接在一起时,链接器将解析对它的引用。
那么它指向了什么呢?
它指向一个数组,其中包含关于每个字符的信息。每个字符都有自己的条目。条目是字符特征的位图表示。例如:如果设置了第5位,就意味着该字符是一个控制字符。另一个例子:如果设置了位0,则意味着字符是上字符。
因此,像(_ctype_ + 1)['x']这样的东西将获得适用于'x'的特性。然后按位执行,以检查是否设置了位5,即检查它是否是控制字符。
添加1的原因可能是实际索引0是为某些特殊目的保留的。
https://stackoverflow.com/questions/58879670
复制相似问题