似乎strncmp
通常推荐比strcmp
,有什么优势?我认为这可能与安全有关。如果是这种情况,如果已知输入字符串之一是文字常量,它是否仍然适用,例如"LiteralString"
?
更新:
我的意思是在需要比较整个字符串的相同用户场景下,strncmp
可以如下使用。我想知道这是否有意义。
strncmp(inputString, "LiternalString", strlen("LiternalString"));
似乎strncmp
通常推荐比strcmp
,有什么优势?我认为这可能与安全有关。如果是这种情况,如果已知输入字符串之一是文字常量,它是否仍然适用,例如"LiteralString"
?
更新:
我的意思是在需要比较整个字符串的相同用户场景下,strncmp
可以如下使用。我想知道这是否有意义。
strncmp(inputString, "LiternalString", strlen("LiternalString"));
问题strcmp
在于,有时,如果错误地传递的参数不是有效的 C 字符串(意味着 p1 或 p2 没有以空字符终止,即不是以NULL 结尾的 String),那么 strcmp 会继续比较,直到达到不可访问的内存和崩溃或有时会导致意外行为。
使用strncmp
您可以限制搜索,使其不会到达不可访问的内存。
但是,据此,不应断定strcmp
使用不安全。这两个功能都以它们预期的方式运行良好。程序员man
在使用该函数之前应阅读该函数的页面,并且在将参数传递给此类库函数时必须足够真诚。
您还可以阅读包含几乎类似问题的THIS 。
strncmp
没有“优势strcmp
”;而是他们解决不同的问题。strcmp
用于确定两个字符串是否相等(如果不相等,可能如何对它们进行排序/排序)。strncmp
(主要)用于确定字符串是否以特定前缀开头。例如:
if (strncmp(str, "--option=", 9)==0)
将确定是否str
以"--option="
. 如果不strcmp
修改要检查的字符串(这可能不是有效操作)或制作无用的副本,这是无法实现的。memcmp
除非您已经知道str
指向长度至少为 9 个字节的对象,否则它也无法实现;否则调用memcmp
将具有未定义的行为。
还有其他用例strncmp
,例如使用非 C 字符串数据。
...在需要比较整个字符串的相同用户场景下,...
strncmp(inputString, "LiternalString", strlen("LiternalString"));
考虑 stringinputString
比string literal长的情况。
const char *inputString = "LiternalString_XYZ";
int cmp = strncmp(inputString, "LiternalString", strlen("LiternalString"));
printf("%d\n", cmp); // prints 0.
但是 OP 想要比较整个字符串。
const char *inputString = "LiternalString_XYZ";
int cmp = strcmp(inputString, "LiternalString");
printf("%d\n", cmp); // prints non-zero.
OP直接问题的结论
我想知道这是否有意义。
不。要比较整个字符串,strncmp()
无法始终提供正确的结果。使用strcmp()
.
更远
strncmp(s1,s2,n)
可以限制搜索,以便在正确计算的情况 下它不会到达不可访问的内存n
——这在 OP 的代码中没有完成,并且当最好n
的s1
和s2
.
大小限制n
适用于两者s1
,s2
因此使此函数可用于比较前缀,但不是“更安全”。
在 OP 的情况下,由于字符串文字的字符串长度,没有理由因为“安全”而限制搜索,因为字符串文字 总是包含终止的null 字符。
如果有的话,n
应该是基于inputString
.
类似的代码strncmp(s1, string_literal, strlen(s1))
在功能上不正确,因为比较错过了空字符。稍微好一点的是strncmp(s1, string_literal, strlen(s1)+1)
,但这在功能上与更简单的相同,strcmp(s1, string_literal)
而不会降低“安全性”。
以下提供了一些改进的“安全性”,以防foo()
没有正确形成 字符串N != M
,但如果如上所述,则可以提供错误的答案。
char s1[N];
foo(s1); // populate s1 somehow
int cmp = strncmp(s1, string_literal, sizeof s1);
char s1[N];
char s2[M];
foo(s1); // populate s1 somehow
foo(s2); // populate s2 somehow
int cmp = strncmp(s1, s2, min(sizeof s1, sizeof s2));
然而在这些情况下,问题出在foo()
,而不是在这里。
对我来说,如果foo()
有问题,我会使用以下
s1[sizeof s1 - 1] = '\0';
s2[sizeof s2 - 1] = '\0';
int cmp = strcmp(s1, s2);
或检测到foo()
没有形成字符串。
char s1[N];
foo(s1);
if (memchr(s1, '\0', sizeof s1) == NULL) Oops();
故事的寓意:strncmp()
不是strcmp()
. 它是用于不同工作的工具:比较字符串前缀。
只需在此处发布一个反 strncmp 用例。想想下面的代码。
#include <stdio.h>
#include <dirent.h>
int main()
{
//I want to list all files under current folder, include hidden files.
DIR *dir;
struct dirent *dp;
char * file_name;
dir = opendir(".");
while ((dp=readdir(dir)) != NULL) {
printf("debug: %s\n", dp->d_name);
if ( !strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..") )
//It doesn't work if you replace strcmp with strncmp here.
//if ( !strncmp(dp->d_name, ".", 1) || !strncmp(dp->d_name, "..", 2) )
{
} else {
file_name = dp->d_name;
printf("file_name: \"%s\"\n",file_name);
}
}
closedir(dir);
return 0;
}
int ret1, ret2;
char dev1[] = { "ABC" };
char dev2[4] = { "ABC" };
dev2[3] = 'D';
ret1 = strncmp(dev1,dev2,strlen(dev1)); // # of characters
ret2 = strncmp(dev1,dev2,sizeof(dev1)); // # of characters plus '\0'
假设: dev1 是空终止的,而 dev2 可能不是。ret1 = 0(假阳性结果),而不是 ret2=-1(有效结果)
fazit:strncmp 不仅仅是 strcmp 的一种更安全的方式。取决于你如何使用它。
我会在字符串上使用 strcmp,在子字符串搜索上使用 strncmp。
如果参数之一不是以空字符结尾的字符串,strcmp 可能会导致存储波动和分段错误。看看为什么你应该使用 strncpy 而不是 strcpy。strcmp 中不太可能发生后果,但问题是相同的。strnxxx 函数族尝试防止读取/写入未获取的内存。
使用 strn 的缺点是对计数器进行额外的比较和减量操作。
简而言之:strncmp 比 strcmp 更安全,但也更慢。
我只能看到一个优势,strncmp 的执行时间比 strcmp 的执行时间略短,因为我们总是将字符串的前缀与 comapre 进行比较,而不是整个字符串。
我不认为 strcmp 和 strncmp 算法涉及任何安全方面。它们是相同的,只是在 strncmp 中只比较前 'n' 个字符。