为啥在这个 C 代码中字母表被分成多个范围?
Posted
技术标签:
【中文标题】为啥在这个 C 代码中字母表被分成多个范围?【英文标题】:Why is the alphabet split into multiple ranges in this C code?为什么在这个 C 代码中字母表被分成多个范围? 【发布时间】:2015-07-15 00:13:34 【问题描述】:在一个自定义库中我看到了一个实现:
inline int is_upper_alpha(char chValue)
if (((chValue >= 'A') && (chValue <= 'I')) ||
((chValue >= 'J') && (chValue <= 'R')) ||
((chValue >= 'S') && (chValue <= 'Z')))
return 1;
return 0;
这是Easter egg 还是与标准 C/C++ 方法相比有什么优势?
inline int is_upper_alpha(char chValue)
return ((chValue >= 'A') && (chValue <= 'Z'));
【问题讨论】:
请注意,在 EBCDIC 中,小写字母的字符范围在大写字母的字符范围之前,并且都在数字之前——这与 ASCII 中的顺序正好相反——基于编码(例如 8859-x 系列、Unicode、CP1252 或……)。 注意:如果'J' - 'I'
和'S' - 'R'
都等于1
,那么我希望一个合理的优化器会将前者变成后者。
【参考方案1】:
这段代码的作者大概不得不在某个时候支持EBCDIC,其中字母的数值是不连续的(I
、J
和R
、S
之间存在间隙,你可能已经猜到了)。
值得注意的是,C 和 C++ 标准仅保证字符 0
到 9
正是出于这个原因具有连续的数值,因此这两种方法都不是严格符合标准的。
【讨论】:
真正的WTF是为什么原作者没有发表评论:// In the EBCDIC coding, the alphabet has gaps between these values. See URL: xxxx for details
。那么你甚至不必问这个问题。您将在代码中找到答案。
@abelenky 如果代码最初是用于通常使用 ebcdic 的系统,那么它在当时可能看起来很明显并且不需要注释,不幸的是,在遗留代码中看起来很好的事情现在看起来很奇怪。
@abelenky:真正的 WTF是为什么原作者没有使用标准功能,即return ( isalpha( chValue ) && isupper( chValue ) )
...
@Damon:这不是问题所在。即使在本机不使用该编码的系统上,您也可能必须处理“外来”编码。所以你将你的语言环境设置为给定的编码,然后你必须保持手指交叉,程序员实际上使用标准函数而不是像上面那样进行“智能”编码,认为他知道他的程序将遇到的每一种编码......
如果从 1970 年代开始编写它以支持 EBCDIC,那么 isalpha 和 isupper 甚至是 ANSI 还是当时大多数编译器都支持?【参考方案2】:
看起来它试图同时覆盖 EBCDIC 和 ASCII。您的替代方法不适用于 EBCDIC(它有误报,但没有误报)
C 和 C++ 做要求'0'-'9'
是连续的。
请注意,标准库调用确实知道它们是否在 ASCII、EBCDIC 或其他系统上运行,因此它们更便携,可能更高效。
【讨论】:
std::isupper
实际上是查询当前安装的全局C语言环境。
是的,你是对的。该方法是为覆盖两种编码而编写的。感谢您的回答!
@Lingxi:没错,但这并不意味着您可以将语言环境从 ASCII 切换到 EBCDIC。 'A'
必须保持 'A'
与区域设置无关。 ASCII 转 UTF-8,这是可能的。
@Lingxi:std::isupper
查询当前安装的全局C语言环境,是的,但是解释字符文字的编译阶段没有。
@Lingxi - 请注意。在大多数情况下是否真的需要std::isupper
是值得怀疑的。它尊重用于用户输入的语言环境。但是在解析文件、与数据库交互时,您通常需要一些其他语言环境。此外,至少在 Linux 上,这些与语言环境相关的调用非常慢 - 例如,std::isalpha
在实际比较单个字符之前调用了两次 dynamic_cast 以“找到”正确的语言环境实现。以上是关于为啥在这个 C 代码中字母表被分成多个范围?的主要内容,如果未能解决你的问题,请参考以下文章