该strncmp()
函数实际上只有一个用例(用于字典顺序):
其中一个字符串的长度已知,† 另一个字符串已知为 NUL 终止。(作为奖励,已知长度的字符串根本不需要以 NUL 结尾。)
我相信只有一个用例的原因(前缀匹配检测不是字典顺序):‡ (1) 如果两个字符串都是 NUL 终止的,strcmp()
应该使用它,因为它会正确地完成工作;(2) 如果两个字符串的长度都已知,memcmp()
则应该使用,因为这样可以避免对 NUL 进行不必要的逐字节检查。
我正在寻找一种惯用(且可读)的方式来使用该函数正确地按字典顺序比较两个这样的参数(其中一个是 NUL 终止的,其中一个不一定是 NUL 终止的,具有已知的长度)。
成语存在吗?如果是这样,它是什么?如果不是,它应该是什么,或者应该使用什么?
简单地使用 的结果是strncmp()
行不通的,因为在已知长度的参数比 NUL 终止的参数短的情况下,它会导致错误的相等结果,并且它恰好是一个前缀。因此,需要额外的代码来测试这种情况。
作为一个独立的功能,我认为这种结构没有太大问题,而且它看起来很惯用:
/* s1 is NUL terminated */
int variation_as_function (const char *s1, const char *s2, size_t s2len) {
int result = strncmp(s1, s2, s2len);
if (result == 0) {
result = (s1[s2len] != '\0');
}
return result;
}
但是,当将此构造内联到代码中时,它会导致双重测试0
何时需要特殊操作:
int result = strncmp(key, input, inputlen);
if (result == 0) {
result = (key[inputlen] != '\0');
}
if (result == 0) {
do_something();
} else {
do_something_else();
}
内联调用的动机是因为独立函数是深奥的:哪个字符串参数是 NUL 终止的,哪个不是。
请注意,问题不是关于性能,而是关于编写惯用代码和采用编码风格的最佳实践。我看到比较中有一些 DRY 违规。有没有一种简单的方法来避免重复?
† 通过known length,我的意思是长度是正确的(没有嵌入的 NUL 会截断长度)。换句话说,输入在程序中的某个较早时间点进行了验证,并记录了它的长度,但输入没有显式地以 NUL 终止。作为一个假设的例子,文本流上的扫描仪可能具有此属性。‡ 正如addy2012
所指出的,可用于前缀匹配。我专注于字典顺序。但是,(1)如果前缀字符串的长度用作长度参数,则两个参数都需要以 NUL 结尾,以防止读取比前缀字符串短的输入字符串。(2) 如果已知前缀字符串和输入字符串之间的最小长度,则strncmp()
memcmp()
在以更少的 CPU 成本提供等效功能并且不损失可读性方面,这将是一个更好的选择。