使用sscanf解析字符串好吗?

is it good to use sscanf for parsing string

本文关键字:字符串 sscanf 使用      更新时间:2023-10-16

我一直在我的解析器中使用sscanf()来获得一些css像标记,如颜色代码下面的一些变化;

#FDC69A
#ff0
orange

示例代码为;

int r g b;
cosnt char* s = "#FAFAFA";
if(sscanf(s, "#%02x%02x%02x", &r, &g, &b) == 3){
// color code ok
}

我当前项目的首选语言是c++,我认为sscanf可以比普通字符逐字符解析更快,整体代码将没有bug &尽管如此,它可能有跨不同编译器的可移植性问题。

我注意到的一件事是,流行的开源项目不使用sscanf对输入缓冲区进行标记,而是逐个字符地进行标记,使用sscanf进行解析是一种糟糕的编程实践,我遵循?

sscanf(以及scanffscanf)的最大问题是数字溢出导致未定义行为。例如:

const char *s = "999999999999999999999999999999";
int n;
sscanf(s, "%d", &n);

C标准没有明确说明这段代码的行为。它可能会将n设置为某个任意值,它可能会报告错误,或者它可能会崩溃。

(在实践中,现有的实现可能表现得很合理,对于某些"合理"的值。)

if(sscanf(s, "#%02x%02x%02x", &r, &g, &b) == 3)是健壮的…没什么好担心的。

从历史上看,这些函数最大的问题是有人可能指定了一个与参数不匹配的格式标志(例如%d没有给出int*)…许多现代编译器都有足够的验证来避免这样的事故。

尽管如此,c++仍然有iostreams,人们倾向于在许多I/O和解析操作中使用它们,因为流析构函数会自动刷新和关闭文件以及释放描述符,它们是类型安全的,可扩展到用户定义的类型,您通常可以为任何类型的流重用解析/输出代码,而且它们通常很方便。不过,对于你上面的特定测试来说,它们要乏味得多。

如果你注意到很多OSS程序一个字符一个字符地扫描,这可能是因为:

  • 他们正在做更复杂的解析-他们想要在读取单个字符后分支到不同的解析逻辑,或者

    • 在你的代码中,你有一个坚定的期望,所以做一个sscanf来测试是合理的,但是如果你写一个编译器,它会太慢,尝试一个巨大的if/else列表,数百sscanf尝试识别令牌。

,

  • scanf, fscanf相关,但 sscanf -避免扫描太远,以便它们可以ungetc,这(从内存中)只能移植保证为1个字符工作。