我是否正确地认为strcmp对于字面值是等效的(且安全的)?

17
我们都知道溢出问题可能会引发的麻烦,这就是为什么strn*存在的原因,而且大多数情况下它们是有意义的。但是,我看到过一些代码使用strncmp来比较命令行参数,如下所示:
if(... strncmp(argv[i], "--help", 6) == 0

现在,我认为这是不必要的,甚至可能是危险的(对于较长的参数,很容易在文字量上出错)。

strncmp会在遇到空字符时停止,代码已经假定argv [i]以空字符结尾。任何字符串文字都保证以空字符结尾,那么为什么不使用strcmp呢?

也许我错过了什么,但我已经看到过几次了,这次引起了我的兴趣。

9个回答

21

是的,这是完全安全的并且被认为是标准做法。字符串字面值保证被正确地以 null 结尾。


12

您确定该代码不是旨在匹配"--helpmedosoemthingwithareallylongoptionname"吗?


这似乎是一个明显的可能性。 - nobody
这是一个非常好的观点。在这种情况下,我不认为会有问题,因为所有的命令行参数都是这样完成的。 - Draemon
1
更可能的意图是匹配类似于 --help=foobar 的内容,但不幸的是它也会匹配类似于 --helper-program 的内容。我认为这段代码有缺陷。 - R.. GitHub STOP HELPING ICE

4

您说得对。

此外,您提供的示例将匹配“--help”,但也会匹配所有以“--help”开头的内容(例如“--help-me”)。

这是一种罕见的情况,在这种情况下,过度热衷于等于错误。


1
据我所知,你是完全正确的--没有理由使用strncmp而不是strcmp。或许人们只是过于谨慎(这并不一定是坏事)。

1

正如其他人所说,strcmp()与文字常量一起使用是完全安全的。如果你想使用strncmp(),可以尝试以下代码:

strncmp(argv[i], "--help", sizeof("--help"))

让编译器为你计数吧!
这只会匹配精确字符串“--help”。如果你想匹配所有以"--help"开头的字符串(如你的代码所做),请使用sizeof() - 1来不包含最后一个'\0'

1
你的意思是 sizeof("--help") - 1,因为 sizeof 包括空终止符。 - Evan Teran
@Evan:取决于你想做什么 - 我已经编辑了我的答案 ;) - Christoph
那么为什么一开始要使用strncmp()呢?这样更冗长和多余。如果你只想匹配完全相同的字符串,就直接使用strcmp()即可。 - Colin D Bennett

0

是的,字面值的存在限制了与字面值大小相比较的数据的大小。在这里使用stncmp是多余的。

有人可能会说,使用strncmp是一个好习惯,但与计算字符的麻烦相比,这个好处微不足道。


0
如果我经常使用strncmp并且不想进行字符计数,我可能会用C语言编写类似这样的代码:
if(... strncmp(argv[i], "--help", sizeof("--help") - 1) == 0 

但这种方法不必要地迭代了两次字符串。至少使用(sizeof("--help")-1)。是的,sizeof在字符串字面量上可以正确工作,因为它们的大小在编译时已知。 - Evan Teran
不过,strlen 函数不会计算空字符。 - Evan Teran
我不确定对于字符串字面值使用sizeof是否合适。一般来说,我建议使用C++和std::string。 :-) - Paul Nathan
sizeof("--help") - 1 可以匹配任何以 "--help" 开头的字符串,而仅使用 sizeof("--help") 则包括了空终止符,只能匹配 "--help"。这似乎是更常见的用法。 - Craig B

0

这可能并不是出于安全考虑。这可能是为了仅检查命令行参数的开头而完成的。许多程序只检查命令行开关的开头,忽略其余部分。


0

嗯...从技术角度来说,这种事情可能发生吗?

char *cp1 = "help";
cp1[4] = '!'; // BAD PRACTICE! don't try to mutate a string constant!
// Especially if you remove the terminating null!
  ...
strcmp(some_variable, "help"); 
// if compiler is "smart" enough to use the same memory to implement
// both instances of "help", you are screwed...

我猜这是一种病态情况和/或垃圾输入,垃圾输出(“医生,当我用头撞墙时很疼!”“那就别这么做!”)...

(附言:我只是提出这个问题--如果你觉得这篇文章让事情变得更加混乱,请适当评论,我会删除它)


由于字符串修改是被禁止的,所以我认为你不能说其他代码是错误的,因为它受到了影响。这就像说一个程序存在错误,因为它可以通过利用另一个程序中的缓冲区溢出来执行。 - Draemon
如果这两个字符串存储在同一个位置,那么修改会影响到两个字符串,并且比较结果仍然相等 - 或者你会得到一个核心转储。当然,这种行为是未定义的;任何事情都有可能发生 - 如果你愿意,可以搜索“鼻妖”。 - Jonathan Leffler
一个这样做的程序是不完整的,因此就你的程序而言,所有逻辑都在那里结束了。 - Thomas

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