根据我的理解,strcmp()
(没有'n'(在任何一个参数中看到空字符时,会立即停止处理并返回结果。
因此,如果其中一个参数 100% 确定为以 null 结尾(例如,它是一个字符串文字(,那么使用 strncmp()
(带有"n"(并调用 strlen()
作为第三个参数的一部分来限制对已知字符串长度的比较没有任何安全好处,因为strcmp()
已经永远不会读取比该已知终止字符串中更多的字符。
事实上,在我看来,调用长度参数是前两个参数之一strlen()
strncmp()
与strcmp()
情况的唯一不同之处在于,它通过计算strlen()
表达式在已知终止字符串的大小上浪费时间线性。
考虑:
示例代码 A:
if (strcmp(user_input, "status") == 0)
reply_with_status();
示例代码 B:
if (strncmp(user_input, "status", strlen("status")+1) == 0)
reply_with_status();
前者比后者有什么好处吗?因为我经常在其他人的代码中看到它。
我对这些功能的工作原理是否有错误的理解?
在您的特定示例中,我会说使用strncmp
是有害的,因为:
- 无论如何,使用
strlen
进行扫描 - 字符串文字
"status"
的重复 - 加 1 以确保字符串确实相等
所有这些都增加了混乱,在这两种情况下,如果它确实少于 6 个字符并且包含与测试字符串相同的字符,则这两种情况都不会保护您免受溢出user_input
。
那将是例外。 如果您知道输入字符串的内存始终多于测试字符串中的字符数,请不要担心。 否则,您可能需要担心,或者至少考虑一下。 strncmp
对于测试大型缓冲区内的内容很有用。
我更喜欢代码可读性。
是的,确实如此。 如果在 strncmp 中使用 strlen,它将遍历指针,直到它在字符串中看到空值。 这使得它在功能上等同于strcmp。
在你给出的特殊情况下,它确实是无用的。 但是,轻微的改变更为常见:
if (strncmp(user_input, "status", strlen("status")) == 0)
reply_with_status();
这个版本只是检查user_input
是否以"status"
开头,所以它有不同的语义。
除了检查字符串开头是否与输入匹配的技巧之外,strncmp 仅在您不能 100% 确定字符串在其分配的空间结束之前以 null 结尾时才有用。
因此,如果您有一个固定大小的缓冲区,并且您接受了用户输入,则可以使用:
strncmp(user_input, "status", sizeof(user_input))
因此,请确保您的比较不会溢出。
但是,在这种情况下,您必须小心,因为如果您的user_input不是null终止的,那么它将真正检查user_input是否与状态的开头匹配。
更好的方式可能是说:
if (user_input[sizeof(user_input) - 1] != ' ') {
// handle it, since it is _not_ equal to your string
// unless filling the buffer is valid
}
else if (strcmp(user_input, "status")) { ... }
现在,我同意这不是 strncmp(( 的特别有用的用途,而且我看不到它比 strcmp(( 有任何好处。
但是,如果我们通过删除+1
来更改代码 strlen
,那么它开始有用。
strncmp(user_input, "status", strlen("status"))
因为这将user_input
的前 6 个字符与"状态"进行了比较——至少有时是有意义的。
因此,如果+1
存在,它就会成为常规strcmp
- 这只是浪费时间计算长度。但是如果没有+1
,这是一个非常有用的比较(在适当的情况下(。
strncmp(( 的使用有限。如果正常的 strcmp(( 在两个字符串中的任何一个上遇到 NUL 将停止。(在这种情况下,字符串是不同的(strncmp(( 将停止并返回零("字符串在前 N 个字符中相等"(
stncmp(( 的一个可能用途是解析选项,直到非有效部分,例如
if (!strncmp("-st", argv[xx], 3)) {}
,这将为"-string"或"-state"或"-st0"返回零,但不为"-sadistic"返回零。