C语言 strcmp 有什么问题?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24353504/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's wrong with strcmp?
提问by David Cary
In the responses to the question Reading In A String and comparing it C, more than one person discouraged the use of strcmp(), saying things like
在对Reading In A String and compare it C问题的回答中,不止一个人不鼓励使用strcmp(),说诸如
I also strongly, strongly advise you to get used to using strncmp() now, ... to avoid many problems down the road.
我也强烈建议您现在就习惯使用 strncmp(),...以避免以后出现许多问题。
or (in Why does my string comparison fail?)
或(在为什么我的字符串比较失败?)
Make certain you use strncmp and not strcmp. strcmp is profoundly unsafe.
确保您使用 strncmp 而不是 strcmp。strcmp 非常不安全。
What problems are they alluding to?
他们暗指什么问题?
The reason scanf()with string specifiersand gets()are strongly discouragedis because they almost inevitably lead to buffer overflow vulnerabilities. However, it's not possible to overflow a buffer with strcmp(), right?
之所以scanf()用绳子符和gets()强烈劝阻,是因为他们几乎不可避免地导致缓冲区溢出漏洞。但是,不可能用 溢出缓冲区strcmp(),对吗?
"A buffer overflow, or buffer overrun, is an anomaly where a program, while writing data to a buffer, overruns the buffer's boundary and overwrites adjacent memory."
“缓冲区溢出或缓冲区溢出是一种异常情况,其中程序在将数据写入缓冲区时,超出了缓冲区的边界并覆盖了相邻的内存。”
( -- Wikipedia: buffer overflow).
( -维基百科:缓冲区溢出)。
Since the strcmp() function never writes to any buffer, the strcmp() function cannot cause a buffer overflow, right?
由于 strcmp() 函数从不写入任何缓冲区,因此 strcmp() 函数不会导致缓冲区溢出,对吗?
What is the reason people discourage the use of strcmp(), and recommend strncmp()instead?
人们不鼓励使用strcmp(),strncmp()而是推荐使用 的原因是什么?
回答by Jonathon Reinhart
While strncmpcan prevent you from overrunning a buffer, its primary purpose isn't for safety. Rather, it exists for the case where one wants to compare only the first N characters of a (properlypossibly NUL-terminated) string.
虽然strncmp可以防止您溢出缓冲区,但其主要目的不是为了安全。相反,它存在,其中一个要比较只有一个(的前N个字符的情况下适当地可能NUL终止)的字符串。
From the man page:
从手册页:
The
strcmp()function compares the two stringss1ands2. It returns an integer less than, equal to, or greater than zero ifs1is found, respectively, to be less than, to match, or be greater thans2.The
strncmp()function is similar, except it compares the only first (at most)nbytes ofs1ands2.
该
strcmp()函数比较两个字符串s1和s2。如果s1发现分别小于、匹配或大于,则返回小于、等于或大于零的整数s2。的
strncmp()功能是相似的,除了它比较仅第一(至多)n的字节s1和s2。
Note that strncmpin this case cannot be replaced with a simple memcmp, because you still need to take advantage of its stop-on-NUL behavior, in case one of the strings is shorter than n.
请注意,strncmp在这种情况下不能用简单的 替换memcmp,因为您仍然需要利用它的 stop-on-NUL 行为,以防其中一个字符串短于n。
If strcmpcauses a buffer overrun, then one of two things is true:
如果strcmp导致缓冲区溢出,则以下两种情况之一为真:
- Your data isn't expected to be NUL-terminated, and you should be using
memcmpinstead. - Your data isexpected to be NUL-terminated, but you've already screwed up when you populated the buffer, by somehow not NUL-terminating it.
- 您的数据不应以 NUL 结尾,而您应该使用它
memcmp。 - 你的数据被预期为NULL结尾的,但你已经搞砸了,当你填入缓冲区,通过某种方式不NUL终止它。
Note that readingpast the end of a buffer is still considered a buffer overrun. While it may seemharmless, it can be just as dangerous as writingpast the end.
请注意,超过缓冲区末尾的读取仍被视为缓冲区溢出。虽然它看起来无害,但它可能和写到最后一样危险。
Reading, writing, executing... it doesn't matter. Any memory reference to an unintended address is undefined behavior. In the most apparent scenario, you attempt to access a page that isn't mapped into your process's address space, causing a page fault, and subsequent SIGSEGV. In the worst case, you sometimes run into a \0 byte, but other times you run into some other buffer, causing inconstant program behavior.
阅读、写作、执行……都无所谓。任何对非预期地址的内存引用都是未定义的行为。在最明显的情况下,您尝试访问未映射到进程地址空间的页面,从而导致页面错误和随后的 SIGSEGV。在最坏的情况下,有时会遇到 \0 字节,但有时会遇到其他缓冲区,从而导致程序行为不稳定。
回答by Keith Thompson
A string is by definition "a contiguous sequence of characters terminated by and including the first null character".
根据定义,字符串是“由第一个空字符终止并包括第一个空字符的连续字符序列”。
The only case where strncmp()would be safer than strcmp()is when you're comparing two character arrays as strings, you're certain that both arrays are at least nbytes long (the 3rd argument passed to strncmp()), and you're notcertain that both arrays contain strings (i.e., contain a '\0'null character terminator).
唯一的情况strncmp()是较安全strcmp()的,当你比较两个字符数组作为字符串,你一定是两个数组都是至少n字节长(第三参数传递给strncmp()),而你没有一定的两个数组包含字符串(即包含'\0'空字符终止符)。
In most cases, your code (if it's correct) will guarantee that any arrays that are supposed to contain null-terminated strings actually do contain null-terminated strings.
在大多数情况下,您的代码(如果它是正确的)将保证任何应该包含以空字符结尾的字符串的数组实际上确实包含以空字符结尾的字符串。
That added nin strncmp()is not a magic wand that makes unsafe code safe. It doesn't guard against null pointers, uninitialized pointers, uninitialized arrays, an incorrect value of n, or just passing incorrect data. You can shoot yourself in the foot with either function.
添加n的strncmp()不是使不安全代码安全的魔杖。它不会防止空指针、未初始化的指针、未初始化的数组、不正确的 值n或只是传递不正确的数据。您可以使用任一功能用脚射击自己。
And if you're trying to call strcmpor strncmpwith an array that you thoughtcontained a null-terminated string but actually doesn't, then your code already has a bug. Using strncmp()might help you avoid the immediate symptom of that bug, but it won't fix it.
如果您尝试调用strcmp或strncmp使用您认为包含以空字符结尾的字符串但实际上不包含的数组,那么您的代码已经存在错误。使用strncmp()可能会帮助您避免该错误的直接症状,但它不会修复它。
回答by Pablo Francisco Pérez Hidalgo
strcmpcompares two strings character to character until a difference has been detected or the \0is found at one of them.
strcmp比较两个字符串的字符到字符,直到检测到差异或\0在其中一个中找到 。
On the other hand, strncmpprovides a way to limit the number of characters to be compared so if the strings do not end with \0the function won't continue checking after the size limit has been reached.
另一方面,strncmp提供了一种限制要比较的字符数的方法,因此如果字符串不以\0函数结尾,则在达到大小限制后将不会继续检查。
Imagine what would happen if you are comparing two strings at this two memory regions:
想象一下,如果您在这两个内存区域比较两个字符串会发生什么:
0x40, 0x41, 0x42,...0x40, 0x41, 0x42,...
0x40, 0x41, 0x42,...0x40, 0x41, 0x42,...
And you are only interested in the two first characters. Somehow \0has been removed from the end of the strings and the third byte happens to coincide at the two regions. strncmpwould avoid comparing this third byte if numparameter is 2.
而你只对前两个字符感兴趣。不知何故\0已从字符串的末尾删除,第三个字节恰好在两个区域重合。strncmp如果num参数为 2,将避免比较第三个字节。
EDITAs the comments below indicate, this situation is derived from a wrong or very concrete use of the language.
编辑正如下面的评论所示,这种情况源于语言的错误或非常具体的使用。

