我正在用C语言在嵌入式系统上为文本文件编写解析器。我需要每秒数百次使用sscanf函数,这会造成性能问题。因此,我正在尝试找到sscanf的快速替代方案。
我需要解析的文本文件包含“ parameter =%d,%d,%d,%d”形式的参数。参数名称的长度有所不同,但参数始终由4个整数值组成。
解析器读取文本文件的一行之后,然后将字符串存储在变量“ token”中。变量“格式”包含形式为“参数=%d,%d,%d,%d”的字符串。
exec
有人知道如何实现快速替代方案吗?
答案 0 :(得分:2)
sscanf()
必须解释与您的token
匹配的格式字符串,并转换字符串内容。您可以使用诸如atoi()
之类的直接转换函数来避免不必要的格式字符串解析:
#include <string.h>
#include <stdlib.h>
void Parser_GetQuadToken( const char* token, int16_t* res1, int16_t* res2, int16_t* res3, int16_t* res4 )
{
char* resstr = strchr( token, '=' ) + 1 ;
*res1 = (int16_t)atoi( resstr ) ;
resstr = strchr( resstr, ',' ) + 1 ;
*res2 = (int16_t)atoi( resstr ) ;
resstr = strchr( resstr, ',' ) + 1 ;
*res3 = (int16_t)atoi( resstr ) ;
resstr = strchr( resstr, ',' ) + 1 ;
*res4 = (int16_t)atoi( resstr ) ;
}
由于目标是提高性能,因此您需要评估改进。我用VC ++在64位调试版本中测得的速度快了9倍,而对32位代码测得的速度快了12倍。目标和编译器的YMMV。优化受库代码的约束几乎没有影响。
请注意,以上实现与原始代码一样多的错误检查功能-也就是没有。您需要确定输入token
将是有效的前提条件。在我的测试中,添加错误检查对性能几乎没有影响:
bool Parser_GetQuadToken( const char* token, int16_t* res1, int16_t* res2, int16_t* res3, int16_t* res4 )
{
char* resstr = 0 ;
if( (resstr = strchr( token, '=' )) != NULL )
{
*res1 = (int16_t)atoi( ++resstr ) ;
if( (resstr = strchr( resstr, ',' )) != NULL )
{
*res2 = (int16_t)atoi( ++resstr ) ;
if( (resstr = strchr( resstr, ',' )) != NULL )
{
*res3 = (int16_t)atoi( ++resstr ) ;
if( (resstr = strchr( resstr, ',' )) != NULL )
{
*res4 = (int16_t)atoi( ++resstr ) ;
}
}
}
}
return resstr != NULL ;
}
但是,它可能不会产生您预期的影响-文件I / O的速度将远远慢于sscanf()
施加的内存和字符串操作-嵌入式系统中sscanf()
的问题更常见所需的代码空间和堆栈使用率。
@SteveSummit建议使用strtol()
。由于这会跟踪扫描到的“最后位置”,以避免重复字符串。您可以利用它来省略对逗号分隔符的显式搜索:
void Parser_GetQuadToken( const char* token, int16_t* res1, int16_t* res2, int16_t* res3, int16_t* res4 )
{
char* resstr = strchr( token, '=' ) ;
*res1 = (int16_t)strtol( ++resstr, &resstr, 10 ) ;
*res2 = (int16_t)strtol( ++resstr, &resstr, 10 ) ;
*res3 = (int16_t)strtol( ++resstr, &resstr, 10 ) ;
*res4 = (int16_t)strtol( ++resstr, &resstr, 10 ) ;
}
在我的测试中,调试速度大约快12倍,优化速度快17倍-但是,这在Windows上是可变的测试。我将保留错误检查供您考虑。