首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >指向数组声明的按位和运算符的指针

指向数组声明的按位和运算符的指针
EN

Stack Overflow用户
提问于 2019-11-15 15:02:18
回答 6查看 338关注 0票数 9

我想了解以下代码:

代码语言:javascript
复制
//...
#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范围内的可打印字母。这是我目前的思维链:

  1. 调用iscntrl( 'a‘),并将’a‘转换为其整数值。
  2. 首先检查_c是否为-1,然后返回0.
  3. 将未定义指针指向的增量增量为1。
  4. 将此入口声明为长度数组(无符号字符)((Int)‘a’)的指针。
  5. 将按位和运算符应用于_C (0x20)和数组(??)

奇怪的是,每次返回0时,给定的字符_c都不是可打印的字符。否则,当它可打印时,函数只返回一个不感兴趣的整数值。我的理解问题在步骤3,4(有点)和5中。

谢谢你的帮助。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 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)的字符都是控制字符。如果不看桌子,这是没有意义的。
  • 任何具有位5集的值都将返回0x20隐藏的值,这是一个非零值。这满足了在布尔值为真的情况下函数返回非零的要求。
票数 3
EN

Stack Overflow用户

发布于 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)

代码将_cint转换为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设置为大写字母,等等。

票数 3
EN

Stack Overflow用户

发布于 2019-11-15 15:40:34

我将从第三步开始:

未定义指针指向的增量增加1。

指针是,而不是未定义的。它只是在其他编译单元中定义的。这就是extern部件告诉编译器的内容。因此,当所有文件链接在一起时,链接器将解析对它的引用。

那么它指向了什么呢?

它指向一个数组,其中包含关于每个字符的信息。每个字符都有自己的条目。条目是字符特征的位图表示。例如:如果设置了第5位,就意味着该字符是一个控制字符。另一个例子:如果设置了位0,则意味着字符是上字符。

因此,像(_ctype_ + 1)['x']这样的东西将获得适用于'x'的特性。然后按位执行,以检查是否设置了位5,即检查它是否是控制字符。

添加1的原因可能是实际索引0是为某些特殊目的保留的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58879670

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档