在使用strncmp()时,如果在表达式中使用strlen()是否会破坏使用strncmp()而不是strcmp()的目的?

7
据我理解,strcmp() (没有'n') 一旦在任意一个参数中看到空字符,就会立即停止处理并返回结果。
因此,如果其中一个参数被100%确定为以空字符结尾(例如字符串字面量),那么使用strncmp()(带有'n')并调用strlen()作为第三个参数来限制比较到已知字符串长度,将不会有任何安全优势,因为strcmp() 永远不会读取比该已知终止字符串中更多的字符。
实际上,我觉得调用strncmp()时,其长度参数是第一/二个参数中strlen()的区别仅在于它通过计算strlen()表达式浪费了与已知终止字符串大小成线性的时间。
考虑以下示例代码A:
if (strcmp(user_input, "status") == 0)
    reply_with_status();

样例代码B:

if (strncmp(user_input, "status", strlen("status")+1) == 0)
    reply_with_status();

前者比后者有什么优势吗?因为我在其他人的代码中看到它反复出现。

我是否对这些函数的工作方式有误解?

6个回答

5
在你的特定例子中,我会说使用strncmp是有害的,因为:
  • 使用strlen无论如何都要扫描
  • 字符串文字"status"的重复
  • 添加1以确保字符串确实相等
所有这些都增加了混乱,并且在任何情况下,如果user_input确实比6个字符短并包含与测试字符串相同的字符,则您都无法受到保护。
那将是个例外。如果您知道您的输入字符串始终具有比测试字符串中的字符数更多的内存,则不用担心。否则,您可能需要担心,或至少要考虑它。 strncmp 对于测试大型缓冲区中的东西非常有用。
我的偏好是代码可读性。

我想给你点赞,但是我的声望值不够。:p 感谢你详细的回答! - cvp
1
一些/大多数编译器可以将strlen("status")计算为常量值。否则,请同意。 - artless noise

4

在你给出的具体情况下,它确实是无用的。但是,稍作修改更为常见:

if (strncmp(user_input, "status", strlen("status")) == 0)
    reply_with_status();

这个版本只是检查user_input是否以"status"开头,所以它有不同的语义。


非常好的观点,我忘了提到。谢谢你的回复! - cvp

4

是的,如果在strncmp中使用strlen函数,它将遍历指针,直到在字符串中看到一个null字符。这使得它在功能上等同于strcmp。


我会说同样的话,然后+1。当我使用strncmp时,第二个参数是用户输入的最大大小(通常只是sizeof(user_input)当user_input是char []时),它是一个守卫。 - philippe lhardy

2

除了用技巧检查字符串的开头是否与输入匹配之外,strncmp仅在您不确定字符串是否在其分配的空间结束之前被终止时才有用。

因此,如果您有一个固定大小的缓冲区来接收用户输入,您可以使用:

strncmp(user_input, "status", sizeof(user_input))

因此,确保您的比较不会溢出。
但在这种情况下,您必须小心,因为如果您的用户输入未以空字符结尾,则实际上将检查用户输入是否与状态的开头匹配。
更好的方法可能是这样说:
if (user_input[sizeof(user_input) - 1] != '\0') {
  // handle it, since it is _not_ equal to your string
  // unless filling the buffer is valid
}
else if (strcmp(user_input, "status")) { ... }

user_input[sizeof(user_input)-1] != '\0',否则您就超出了user_input数组的范围。 - philippe lhardy

0

现在,我同意这不是使用strncmp()的特别有用的用法,我看不出它比strcmp()有任何好处。

然而,如果我们通过删除strlen后面的+1来更改代码,那么它就开始变得有用了。

 strncmp(user_input, "status", strlen("status"))

由于这个比较将user_input的前6个字符与“status”进行比较,至少有时是有意义的。

因此,如果有+1,它就变成了一个常规的strcmp,计算长度只是浪费时间。但是如果没有+1,在正确的情况下,这是一个非常有用的比较。


非常好的观点。这就是实现“输入足够的命令词以区分它”的输入系统的方式,不是吗?假设您没有其他以“st”开头的命令。感谢您的回复! - cvp
是的,虽然这更像伪代码 count = 0; for(i : all_commands) { if (match_cmd(command, i)) { matched = i; count++; } } if (count == 1) execute_command(i); else print("need to type more..."); - Mats Petersson

0

strncmp()的使用有限。正常的strcmp()会在任意两个字符串中遇到NUL时停止(在这种情况下,字符串是不同的)。而strncmp()会在第一个N个字符相等时停止并返回零("字符串在前N个字符中相等")

stncmp()的一个可能用途是解析选项,直到非重要部分,例如

if (!strncmp("-st", argv[xx], 3)) {}

会返回零,如果后缀是"-string" 或者 "-state" 或者 "-st0",但不会对"-sadistic" 返回零。


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