C语言 sscanf 被认为可以安全使用吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5873402/
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
Is sscanf considered safe to use?
提问by nmichaels
I have vague memories of suggestions that sscanfwas bad. I know it won't overflow buffers if I use the field width specifier, so is my memory just playing tricks with me?
我对sscanf不好的建议有模糊的记忆。我知道如果我使用字段宽度说明符它不会溢出缓冲区,那么我的记忆只是在玩弄我吗?
采纳答案by user541686
I think it depends on how you're using it: If you're scanning for something like int, it's fine. If you're scanning for a string, it's not (unless there was a width field I'm forgetting?).
我认为这取决于你如何使用它:如果你正在扫描类似的东西int,那很好。如果您正在扫描字符串,则不是(除非我忘记了宽度字段?)。
Edit:
编辑:
It's not always safe for scanning strings.
扫描字符串并不总是安全的。
If your buffer size is a constant, then you can certainly specify it as something like %20s. But if it's not a constant, you need to specify it in the format string, and you'd need to do:
如果您的缓冲区大小是一个常量,那么您当然可以将其指定为类似%20s. 但如果它不是常量,则需要在格式字符串中指定它,并且需要执行以下操作:
char format[80]; //Make sure this is big enough... kinda painful
sprintf(format, "%%%ds", cchBuffer - 1); //Don't miss the percent signs and - 1!
sscanf(format, input); //Good luck
which is possible but veryeasy to get wrong, like I did in my previous edit (forgot to take care of the null-terminator). You might even overflow the format string buffer.
这是可能的,但很容易出错,就像我在之前的编辑中所做的那样(忘记处理空终止符)。您甚至可能会溢出格式字符串缓冲区。
回答by z33m
The reason why sscanfmight be considered bad is because it doesnt require you to specify maximum string width for string arguments, which could result in overflows if the input read from the source string is longer. so the precise answer is: it is safe if you specify widths properly in the format string otherwise not.
之所以sscanf可能被认为是不好的,是因为它不要求您为字符串参数指定最大字符串宽度,如果从源字符串读取的输入较长,这可能会导致溢出。所以确切的答案是:如果在格式字符串中正确指定宽度是安全的,否则不安全。
回答by R.. GitHub STOP HELPING ICE
Note that as long as your buffers are at least as long as strlen(input_string)+1, there is no way the %sor %[specifiers can overflow. You can also use field widths in the specifiers if you want to enforce stricter limits, or you can use %*sand %*[to suppress assignment and instead use %nbefore and after to get the offsets in the original string, and then use those to read the resulting sub-string in-place from the input string.
请注意,只要您的缓冲区至少与 一样长strlen(input_string)+1,%s或%[说明符就不可能溢出。如果您想强制执行更严格的限制,您也可以在说明符中使用字段宽度,或者您可以使用%*sand%*[来抑制赋值,而是使用%nbefore 和 after 来获取原始字符串中的偏移量,然后使用它们来读取结果子从输入字符串就地字符串。
回答by Heisenbug
Yes it is..if you specify the string width so the are no buffer overflow related problems.
是的,如果您指定字符串宽度,则不会出现与缓冲区溢出相关的问题。
Anyway, like @Mehrdad showed us, there will be possible problems if the buffer size isn't established at compile-time. I suppose that put a limit to the length of a string that can be supplied to sscanf, could eliminate the problem.
无论如何,就像@Mehrdad 向我们展示的那样,如果在编译时未确定缓冲区大小,可能会出现问题。我想限制可以提供给 sscanf 的字符串的长度可以消除这个问题。
回答by mathk
There is 2 point to take care.
有2点要注意。
The output buffer[s].
输出缓冲区[s]。
As mention by others if you specify a size smaller or equals to the output buffer size in the format string you are safe.
正如其他人所提到的,如果您指定的大小小于或等于格式字符串中的输出缓冲区大小,则您是安全的。
The input buffer.
输入缓冲区。
Here you need to make sure that it is a null terminate string or that you will not read more than the input buffer size.
在这里,您需要确保它是一个空终止字符串,或者您不会读取超过输入缓冲区大小的内容。
If the input string is not null terminated sscanfmay read past the boundary of the buffer and crash if the memorie is not allocated.
如果输入字符串不是空终止,则sscanf可能会读取超出缓冲区的边界并在未分配内存时崩溃。
回答by zwol
All of the scanffunctions have fundamental design flaws, only some of which could be fixed. They should not be used in production code.
所有scanf功能都有基本的设计缺陷,只有其中一些可以修复。它们不应在生产代码中使用。
Numeric conversion has full-on demons-fly-out-of-your-nose undefined behavior if a value overflows the representable range of the variable you're storing the value in. I am not making this up. The C library is allowed to crash your programjust because somebody typed too many input digits. Even if it doesn't crash, it's not obliged to do anything sensible. There is no workaround.
As pointed out in several other answers,
%sis just as dangerous as the infamousgets. It's possibleto avoid this by using either the 'm' modifier, or a field width, but you have to remember to do that for every single text field you want to convert, and you have to wire the field widths into the format string -- you can't passsizeof(buff)as an argument.If the input does not exactly match the format string,
sscanfdoesn't tell you how many charactersinto the input buffer it got before it gave up. This means the only practical error-recovery policy is to discard the entire input buffer. This canbe OK if you are processing a file that's a simple linear array of records of some sort (e.g. with a CSV file, "skip the malformed line and go on to the next one" is a sensible error recovery policy), but if the input has any more structure than that, you're hosed.
如果某个值超出了您存储该值的变量的可表示范围,则数值转换具有全面的恶魔飞出您的鼻子未定义行为。 我不是在编造这个。C 库允许您的程序崩溃,因为有人输入了太多的输入数字。即使它没有崩溃,它也没有义务做任何明智的事情。没有解决方法。
正如其他几个答案中指出的那样,
%s与臭名昭著的gets. 这是可能通过使用中的“m”修饰符,或字段宽度,以避免这一点,但你要记住做就是要转换的每一个文本字段,您必须将字段宽度电线插入格式字符串- - 你不能sizeof(buff)作为参数传递。如果输入与格式字符串不完全匹配,
sscanf则不会告诉您它在放弃之前进入输入缓冲区的字符数。这意味着唯一实用的错误恢复策略是丢弃整个输入缓冲区。这可能是确定的,如果你正在处理的文件是一个简单的线性的某种记录阵列(CSV文件例如,“跳过畸形线,并继续到下一个”是一个明智的错误恢复策略),但如果输入有更多的结构,你被灌输了。
In C, parse jobs that aren't complicated enough to justify using lexand yaccare generally best done either with POSIX regexps (regex.h) or with hand-rolled string parsing. The strto*numeric conversion functions dohave well-specified and useful behavior on overflow and dotell you how may characters of input they consumed, and string.hhas lots of handy functions for hand-rolled parsers (strchr, strcspn, strsep, etc).
在 C 中,解析工作不够复杂以证明使用是合理的lex,yacc通常最好使用 POSIX 正则表达式 ( regex.h) 或手动字符串解析来完成。该strto*数值转换函数也有溢流井指定的和有益的行为和做告诉你有多他们消耗输入字符,并且string.h有很多方便的功能手卷解析器(strchr,strcspn,strsep等)。

