最大限度地减少sscanf上的内存消耗

时间:2017-04-07 13:30:38

标签: c parsing memory scanf

我有从GSM模块获取的时间和日期字符串。

以下是时间和日期格式:

"yy/MM/dd,hh:mm:ss±zz"

示例字符串:

"+CCLK: "17/04/07,12:57:43+03""

我需要解析它并将其转换为Unix时间戳。我有以下实现,它运作良好:

时间结构:

struct timeStruct{

uint16 Year;
uint8 Month;
uint8 Day;
uint8 Hour;
uint8 Minute;
uint8 Second;
};

GSM时钟命令解析器:

void load_clock(void)
{

struct timeStruct gsmTimeStruct;

/* Parse year,month,day,hour,minute,second and GMT timezone */
sscanf(gsm_clk_string, "+CCLK: \"%hd/%d/%d,%d:%d:%d%c%d", &(gsmTimeStruct.Year), &(gsmTimeStruct.Month), &(gsmTimeStruct.Day), &(gsmTimeStruct.Hour), &(gsmTimeStruct.Minute), &(gsmTimeStruct.Second),&CONEZONE,&TIMEZONE);

unixTime = (uint32_t)RTC_DateTimeToUnix(gsmTimeStruct);

/* Collect GMT difference */
if(CONEZONE == '+')
    unixTime = unixTime - TIMEZONE*3600;
else
    unixTime = unixTime + TIMEZONE*3600;

}

sscanf函数从闪存中消耗1776字节,这对于这个MCU来说是一个巨大的数字。 Unix转换函数也消耗大约700字节,但它有点正常,因为它有一些数学计算。

在没有消耗如此大的闪存使用量的情况下解析这个字符串有什么好主意吗?

注意:命令字符串的错误检查不是问题,因为GSM模块已经这样做了。因此,如果我们想要更改解析实现,我们不必这样做。我们可以假设这些数字总是在那里。

编辑:我在下面尝试了片段,效果很好。它节省了1.7千字节的内存,但我不确定这是否是一种正确的方法。

gsmTimeStruct.Year      = (gsm_clk_string[8]-'0')*10 + (gsm_clk_string[9]-'0');
gsmTimeStruct.Month     = (gsm_clk_string[11]-'0')*10 + (gsm_clk_string[12]-'0');
gsmTimeStruct.Day       = (gsm_clk_string[14]-'0')*10 + (gsm_clk_string[15]-'0');
gsmTimeStruct.Hour      = (gsm_clk_string[17]-'0')*10 + (gsm_clk_string[18]-'0');
gsmTimeStruct.Minute    = (gsm_clk_string[20]-'0')*10 + (gsm_clk_string[21]-'0');
gsmTimeStruct.Second    = (gsm_clk_string[23]-'0')*10 + (gsm_clk_string[24]-'0');
TIMEZONE                = (gsm_clk_string[26]-'0')*10 + (gsm_clk_string[27]-'0');
CONEZONE                = gsm_clk_string[25];

1 个答案:

答案 0 :(得分:0)

我认为你需要的就是这个,只需相应地移动char ptr。 在下面的代码示例中,我假设gsm_clk_string中的第一个字符是"

/*                     "+CCLK: "2017/04/07, 12:57:43+03""    */
/*  gsm_clk_string[] : 0123456789012345678902134567890123    */

char *ptr;

ptr = gsm_clk_string;
ptr += 9;

gsmTimeStruct.Year = (uint16) ((*ptr - '0') * 1000);
ptr++;
gsmTimeStruct.Year += (uint16) ((*ptr - '0') * 100);
ptr++;
gsmTimeStruct.Year += (uint16) ((*ptr - '0') * 10);
ptr++;
gsmTimeStruct.Year += (uint16) ((*ptr - '0'));

ptr += 2;

gsmTimeStruct.Month = (uint8) ((*ptr - '0') * 10);
ptr++;
gsmTimeStruct.Month += (uint8) (*ptr - '0');

ptr += 2;

gsmTimeStruct.Day = (uint8) ((*ptr - '0') * 10);
ptr++;
gsmTimeStruct.Day += (uint8) (*ptr - '0');

ptr += 3;

gsmTimeStruct.Hour = (uint8) ((*ptr - '0') * 10);
ptr++;
gsmTimeStruct.Hour += (uint8) (*ptr - '0');

ptr += 2;

gsmTimeStruct.Minute = (uint8) ((*ptr - '0') * 10);
ptr++;
gsmTimeStruct.Minute += (uint8) (*ptr - '0');

ptr += 2;

gsmTimeStruct.Second = (uint8) ((*ptr - '0') * 10);
ptr++;
gsmTimeStruct.Second += (uint8) (*ptr - '0');

ptr++;

if ( *ptr == '+' )
{
   ptr++;
   TIMEZONE = (whatever_type_TimeZone) ((*ptr - '0') * 10);
   ptr++
   TIMEZONE += (whatever_type_TimeZone) ((*ptr - '0'));

   unixTime = (uint32_t) RTC_DateTimeToUnix( gsmTimeStruct ) - ( TIMEZONE * 3600 );    
}
else if ( *ptr == '-' )
{
   ptr++;
   TIMEZONE = (whatever_type_TimeZone) ((*ptr - '0') * 10);
   ptr++
   TIMEZONE += (whatever_type_TimeZone) ((*ptr - '0'));

   unixTime = (uint32_t) RTC_DateTimeToUnix( gsmTimeStruct ) + ( TIMEZONE * 3600 );
}
else
{
    /* problem */
}