为什么在这段C代码中字母表被分成多个范围?

160

我在一个自定义库中看到了一个实现:

inline int is_upper_alpha(char chValue)
{
    if (((chValue >= 'A') && (chValue <= 'I')) ||
        ((chValue >= 'J') && (chValue <= 'R')) ||
        ((chValue >= 'S') && (chValue <= 'Z')))
        return 1;
    return 0;
}

那是一个彩蛋吗?与标准的C/C++方法相比,有哪些优势?

inline int is_upper_alpha(char chValue)
{
    return ((chValue >= 'A') && (chValue <= 'Z'));
}

请注意,在EBCDIC中,小写字母的字符范围位于大写字母的字符范围之前,两者都位于数字之前 - 这正好与基于ASCII的编码(例如8859-x系列,Unicode,CP1252等)的顺序相反。 - Jonathan Leffler
1
жіЁж„ҸпјҡеҰӮжһң 'J' - 'I' е’Ң 'S' - 'R' йғҪзӯүдәҺ 1пјҢйӮЈд№ҲжҲ‘еёҢжңӣдёҖдёӘеҗҲзҗҶзҡ„дјҳеҢ–еҷЁе°ҶеүҚиҖ…еҸҳжҲҗеҗҺиҖ…гҖӮ - Matthieu M.
2个回答

215

此代码的作者可能曾经需要支持EBCDIC,其中字母的数字值是不连续的(您可能已经猜到了,IJRS之间存在间隙)。

值得注意的是,C和C++标准仅保证字符09具有连续的数字值,正是出于这个原因,因此这两种方法都不是严格符合标准的。


64
真正让人惊讶的是为什么原作者没有加上这样的注释: "// 在 EBCDIC 编码中,字母之间具有这些值之间的间隔。详情请参见网址:xxxx"。 这样你就不必问这个问题了。 代码中就有内置的答案。 - abelenky
66
如果该代码最初是为通常使用ebcdic的系统编写的,那么当时它可能似乎很明显,而不需要注释。不幸的是,在遗留代码中看起来正常的事情现在看来很奇怪。 - Vality
26
“真正的WTF是为什么原作者没有使用标准功能,即 return ( isalpha( chValue ) && isupper( chValue ) )…” - DevSolar
4
@Damon:那不是问题所在。即使在不使用该编码的系统上,您可能仍需要处理“外来”编码。因此,您需要将您的区域设置为给定的编码,然后您必须祈祷程序员实际上使用了标准函数,而不是像上面那样进行“智能”编码,认为他知道他的程序将遇到的每个编码…… - DevSolar
6
如果它是为了支持1970年代的EBCDIC而编写的,那么isalpha和isupper甚至符合ANSI标准或大多数编译器在当时都支持吗? - nickalh
显示剩余7条评论

54

看起来它试图涵盖EBCDIC和ASCII。您的替代方法对于EBCDIC无效(存在假阳性,但不存在假阴性)

C和C++确实要求'0'-'9'是连续的。

请注意,标准库调用了解它们是否在ASCII、EBCDIC或其他系统上运行,因此它们更具可移植性且可能更高效。


5
std::isupper实际上查询当前安装的全局C语言环境。 - Lingxi
1
是的,你说得对。这个方法是为了覆盖两种编码而编写的。感谢你的回答! - Vladimir Ch.
4
@Lingxi: 的确,但这并不意味着你可以将语言环境从ASCII切换到EBCDIC。无论语言环境如何,'A'都必须保持为'A'。但是,从ASCII到UTF-8的转换是可能的。 - MSalters
2
@Lingxi:std::isupper 查询当前安装的全局 C 区域设置,但解释字符字面量的编译阶段却不会。 - Lightness Races in Orbit
1
@Lingxi - 快速提醒一下。在大多数情况下,std::isupper是否真的需要是有问题的。它尊重用户输入时使用的语言环境。但是,在解析文件、与数据库交互时,通常期望使用其他语言环境。此外,至少在Linux上,这些与语言环境相关的调用非常缓慢-例如,std::isalpha在实际比较单个字符之前会调用dynamic_cast两次以“查找”适当的语言环境实现。 - ibre5041

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接