C语言 strncmp() 有惯用法吗?



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] != '');
}
return result;
}

但是,当将此构造内联到代码中时,当相等需要特殊操作时,它会导致对0进行双重测试:

int result = strncmp(key, input, inputlen);
if (result == 0) {
result = (key[inputlen] != '');
}
if (result == 0) {
do_something();
} else {
do_something_else();
}

内联调用的动机是因为独立函数是深奥的:哪个字符串参数是 NUL 终止的,哪个不是

。请注意,问题不在于性能,而在于编写惯用代码和采用编码风格的最佳实践。我看到比较存在一些 DRY 违规。有没有一种简单的方法来避免重复?


已知长度,我的意思是长度是正确的(没有嵌入的 NUL 会截断长度)。换句话说,输入在程序的某个较早点进行了验证,并记录了其长度,但输入未显式终止 NUL。作为假设示例,文本流上的扫描程序可能具有此属性。
正如addy2012所指出的,strncmp()可用于前缀匹配。我专注于词典排序。但是,(1) 如果前缀字符串的长度用作长度参数,则需要将两个参数都 NUL 终止,以防止读取比前缀字符串短的输入字符串。(2) 如果前缀字符串和输入字符串之间的最小长度已知,那么memcmp()以更低的 CPU 成本提供等效功能且不损失可读性方面将是更好的选择。

strncmp()函数实际上只有一个用例:

其中一个字符串具有已知长度,另一个字符串已知为 NUL 已终止。

不,您可以使用它来比较两个字符串的开头,无论任何字符串的长度是否已知。例如,如果您有一个带有姓氏的数组/列表,并且您想查找所有以"Mac"开头的内容。

事实上,strncmp通常应该优先使用strcmp,除非您绝对知道这两个字符串都是格式正确的并且nul终止。

为什么?因为否则您有缓冲区溢出的漏洞。

不幸的是,这条规则并不经常被遵循。

存在很多缓冲区溢出错误。

更新

我认为这里的核心错误在于"其中一个字符串具有已知长度"。 没有 C 字符串具有先验的已知长度。它们不像 Pascal 或 Java 字符串,它们本质上是一对(长度、缓冲区)。根据定义,C 字符串是标识内存块的char[]可分辨符号来标识末尾。strncmpstrncpy等的存在是为了防止尝试将内存块用作格式不正确的字符串。

相关内容

  • 没有找到相关文章

最新更新