sscanf的快速替代品

时间:2019-11-09 11:32:51

标签: c parsing embedded

我正在用C语言在嵌入式系统上为文本文件编写解析器。我需要每秒数百次使用sscanf函数,这会造成性能问题。因此,我正在尝试找到sscanf的快速替代方案。

我需要解析的文本文件包含“ parameter =%d,%d,%d,%d”形式的参数。参数名称的长度有所不同,但参数始终由4个整数值组成。

解析器读取文本文件的一行之后,然后将字符串存储在变量“ token”中。变量“格式”包含形式为“参数=%d,%d,%d,%d”的字符串。

exec

有人知道如何实现快速替代方案吗?

1 个答案:

答案 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上是可变的测试。我将保留错误检查供您考虑。