strcmp有什么问题?
在阅读字符串中的问题并将其与C进行比较的回答中 ,不止一个人不鼓励使用strcmp()
,说像
我也强烈建议你现在习惯使用strncmp(),以避免很多问题。
或( 为什么我的字符串比较失败? )
确保你使用strncmp而不是strcmp。 strcmp非常不安全。
他们提到了什么问题?
强烈建议不要 使用带字符串说明符和gets()
scanf()
,因为它们几乎不可避免地导致缓冲区溢出漏洞。 但是,使用strcmp()
溢出缓冲区是不可能的,对吗?
“缓冲区溢出或缓冲区溢出是一种exception现象,程序在将数据写入缓冲区时会超出缓冲区的边界并覆盖相邻的内存。”
( – 维基百科:缓冲区溢出 )。
由于strcmp()函数永远不会写入任何缓冲区,strcmp()函数不会导致缓冲区溢出,对吧?
人们不鼓励使用strcmp()
的原因是什么,并推荐使用strncmp()
?
虽然strncmp
可以防止你超越缓冲区,但它的主要目的不是为了安全 。 相反,它存在于人们想要仅比较( 恰当可能是NUL终止的)字符串的前N个字符的情况。
从手册页 :
strcmp()
函数比较两个字符串s1
和s2
。 如果找到s1
则它返回小于,等于或大于零的整数,小于,匹配或大于s2
。
strncmp()
函数类似,只是它比较了s1
和s2
的唯一第一个(最多)n
个字节。
请注意,在这种情况下, strncmp
不能替换为简单的memcmp
,因为如果其中一个字符串短于n
,您仍需要利用其stop-on-NUL行为。
如果strcmp
导致缓冲区溢出,则两件事之一成立:
- 您的数据预计不会被NUL终止,您应该使用
memcmp
。 - 您的数据应该是NUL终止的,但是当您填充缓冲区时,您已经搞砸了,不知道NUL终止它。
请注意,超过缓冲区末尾的读取仍被视为缓冲区溢出 。 虽然它看起来似乎无害,但它可能和写过去一样危险。
阅读,写作,执行……没关系。 对非预期地址的任何内存引用都是未定义的行为。 在最明显的情况下,您尝试访问未映射到进程的地址空间的页面,从而导致页面错误,以及随后的SIGSEGV。 在最坏的情况下,有时会遇到\ 0字节,但有时会遇到其他缓冲区,从而导致程序行为不稳定。
根据定义,字符串是“由第一个空字符终止并包括第一个空字符的连续字符序列”。
strncmp()
比strcmp()
更安全的唯一情况是,当您将两个字符数组作为字符串进行比较时,您确定两个数组的长度至少为n
个字节(第三个参数传递给strncmp()
),并且你不确定两个数组都包含字符串(即包含'\0'
0’null字符终结符)。
在大多数情况下,您的代码( 如果它是正确的 )将保证任何应该包含以null结尾的字符串的数组实际上都包含以null结尾的字符串。
在strncmp()
添加n
并不是一个使不安全代码安全的魔杖。 它不会防止空指针,未初始化的指针,未初始化的数组,不正确的n
值,或者只是传递不正确的数据。 无论哪种function,你都可以用脚射击自己。
如果你试图用你认为包含空终止字符串的数组调用strcmp
或strncmp
但实际上没有,那么你的代码已经有了一个错误。 使用strncmp()
可以帮助您避免该错误的直接症状,但它不会修复它。
strcmp
将两个字符串字符与字符进行比较,直到检测到差异或在其中一个字符处找到\0
。
另一方面, strncmp
提供了一种限制要比较的字符数的方法,因此如果字符串不以\0
结尾,则在达到大小限制后函数将不会继续检查。
想象一下如果你在这两个内存区域比较两个字符串会发生什么:
0x40, 0x41, 0x42,...
0x40, 0x41, 0x42,...
而你只对两个第一个角色感兴趣。 不知何故\0
已从字符串的末尾删除,第三个字节恰好在两个区域重合。 如果num
参数为2, strncmp
将避免比较第三个字节。
编辑正如下面的评论所示,这种情况来自于语言的错误或非常具体的使用。