我一直在我的解析器中使用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可以比常规字符更快地通过字符解析,并且整体代码将是无错误的&最小的是它可能在不同的编译器中存在可移植性问题。
我注意到的一点是,流行的开源项目不使用sscanf来标记输入缓冲区,而是使用char来表示char,使用sscanf解析我正在遵循的编程实践是不好的?
答案 0 :(得分:6)
sscanf
(以及scanf
和fscanf
)的最大问题是数字溢出会导致未定义的行为。例如:
const char *s = "999999999999999999999999999999";
int n;
sscanf(s, "%d", &n);
C标准对此代码的行为完全没有说明。它可能会将n
设置为某个任意值,它可能会报告错误,或者可能会崩溃。
(在实践中,对于某些“理智”的价值,现有的实施可能表现得很明智。)
答案 1 :(得分:1)
if(sscanf(s, "#%02x%02x%02x", &r, &g, &b) == 3)
非常强大......没有什么可担心的。
从历史上看,这些函数最大的担忧是有人可能会指定一个与参数不匹配的格式标志(例如%d
没有给出int*
... ...许多现代编译器都有足够的验证,以避免这样的事故。
仍然,C ++有iostreams,人们倾向于将它们用于许多I / O和解析操作,因为流析构函数会自动刷新和关闭文件和释放描述符,它们是类型安全的,可扩展到用户定义的类型,你通常可以为任何类型的流重用解析/输出代码,并且它们通常很方便。但是,对于上面的特定测试,它们会显得更加乏味。
如果你注意到很多OSS程序逐个字符地扫描,可能是因为:
他们正在进行更复杂的解析 - 他们希望在阅读单个字符后分支到不同的解析逻辑,或者
sscanf
来测试它是合理的,但如果你写的是一个编译器,那么尝试一个巨大的{ {1}} / if
数百else
次尝试识别令牌的列表。
sscanf
相关,scanf
但不 fscanf
- 避免扫描太远以致ungetc,(来自内存)是只能保证可以使用1个字符。