首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >strtol和strtod的ARMCC 5优化

strtol和strtod的ARMCC 5优化
EN

Stack Overflow用户
提问于 2017-05-29 08:57:20
回答 1查看 362关注 0票数 0

我有一个基于STM32L4单片机(超低功耗皮质M4)的板,用于全球导航卫星系统的跟踪。我不使用RTOS,所以我使用自定义调度程序。编译器和环境是KEIL uVision 5(编译器5.05和5.06,行为不改变)

单片机通过普通UART与GNSS模块通信,该协议是NMEA和AT的混合协议。GNSS的位置是纯文本,必须转换成一对浮点/双坐标。要从文本中获取double/float值,我使用strtod (或strtof)。注意,字符串操作是在一个单独的缓冲区中进行的,与UART不同。

UART上纬度的典型字符串是

4256.45783

意思是42°56.45783‘

要获得绝对位置,我使用以下公式

42 + 56.45783 / 60

当没有优化时,代码工作良好,位置被正确转换。当我打开1级优化(或更高)时,如果我使用标准C库,我可以转换整数部分(在本例中为42),当涉及到转换56.45783时,我只得到56 (因此,直到点的整数部分)。

如果我摆脱了标准库,并且使用了从ANSI源代码库下载的自定义strtod函数,那么我只会得到带有ERANGE错误的0。

在代码的其他部分中,我使用strtol,当打开L1优化时,strtol有一个奇怪的行为:当第一个数字为9,转换基为10时,它简单地跳过了与其他数字一起进行的9。

因此,如果在缓冲区中我有92,我将只得到2解析。为了消除这个问题,我只是在数字前面加上了一个符号+,结果总是可以的(据我所知)。这不适用于斯特罗托。

请注意,我尝试使用静态、易失性和堆栈中的变量,行为不会改变。

编辑:我简化了代码,以便得到错误的地方,如下所示

C代码如下所示:

代码语言:javascript
复制
void GnssStringToLatLonDegMin(const char* str, LatLong_t* struc)
{
    double dbl = 0.0;
    dbl = strtod("56.45783",NULL);
    if(struc != NULL)
    {
        struc->Axis = (float)((dbl / 60.0) + 42.0);
    }
}

0级优化:

代码语言:javascript
复制
559: void GnssStringToLatLonDegMin(const char* str, LatLong_t* struc) 
0x08011FEE BDF8      POP           {r3-r7,pc}
560: { 
0x08011FF0 B570      PUSH          {r4-r6,lr}
0x08011FF2 4605      MOV           r5,r0
0x08011FF4 ED2D8B06  VPUSH.64      {d8-d10}
0x08011FF8 460C      MOV           r4,r1
561:         double dbl = 0.0; 
0x08011FFA ED9F0BF8  VLDR          d0,[pc,#0x3E0]
0x08011FFE EEB08A40  VMOV.F32      s16,s0
0x08012002 EEF08A60  VMOV.F32      s17,s1
562:         dbl = strtod("56.45783",NULL); 
0x08012006 2100      MOVS          r1,#0x00 
0x08012008 A0F6      ADR           r0,{pc}+4  ; @0x080123E4
0x0801200A F7FDFED1  BL.W          __hardfp_strtod (0x0800FDB0)
0x0801200E EEB08A40  VMOV.F32      s16,s0 
0x08012012 EEF08A60  VMOV.F32      s17,s1
563:         if(struc != NULL) 
564:         { 
0x08012016 B1A4      CBZ           r4,0x08012042
565:                 struc->Axis = (float)((dbl / 60.0) + 42.0); 
566:         } 
0x08012018 ED9F0BF5  VLDR          d0,[pc,#0x3D4]
0x0801201C EC510B18  VMOV          r0,r1,d8
0x08012020 EC532B10  VMOV          r2,r3,d0
0x08012024 F7FEF880  BL.W          __aeabi_ddiv (0x08010128)
0x08012028 EC410B1A  VMOV          d10,r0,r1
0x0801202C ED9F0BF2  VLDR          d0,[pc,#0x3C8]
0x08012030 EC532B10  VMOV          r2,r3,d0
0x08012034 F7FDFFBC  BL.W          __aeabi_dadd (0x0800FFB0)
0x08012038 EC410B19  VMOV          d9,r0,r1
0x0801203C F7FDFF86  BL.W          __aeabi_d2f (0x0800FF4C)
0x08012040 6020      STR           r0,[r4,#0x00]
567: } 

一级优化

代码语言:javascript
复制
557: void GnssStringToLatLonDegMin(const char* str, LatLong_t* struc) 
0x08011FEE BDF8      POP           {r3-r7,pc}
558: { 
559:         double dbl = 0.0; 
0x08011FF0 B510      PUSH          {r4,lr}
0x08011FF2 460C      MOV           r4,r1
560:         dbl = strtod("56.45783",NULL); 
0x08011FF4 2100      MOVS          r1,#0x00
0x08011FF6 A0F7      ADR           r0,{pc}+2  ; @0x080123D4
0x08011FF8 F7FDFEDA  BL.W          __hardfp_strtod (0x0800FDB0)
561:         if(struc != NULL) 
562:         { 
0x08011FFC 2C00      CMP           r4,#0x00
0x08011FFE D010      BEQ           0x08012022
563:                 struc->Axis = (float)((dbl / 60.0) + 42.0); 
564:         } 
0x08012000 ED9F1BF7  VLDR          d1,[pc,#0x3DC]
0x08012004 EC510B10  VMOV          r0,r1,d0
0x08012008 EC532B11  VMOV          r2,r3,d1
0x0801200C F7FEF88C  BL.W          __aeabi_ddiv (0x08010128)
0x08012010 ED9F1BF5  VLDR          d1,[pc,#0x3D4]
0x08012014 EC532B11  VMOV          r2,r3,d1
0x08012018 F7FDFFCA  BL.W          __aeabi_dadd (0x0800FFB0)
0x0801201C F7FDFF96  BL.W          __aeabi_d2f (0x0800FF4C)
0x08012020 6020      STR           r0,[r4,#0x00]
565: }

我查看了这些函数调用的__hardfp_strtod和__strtod_int的反汇编,由于它们被合并为二进制文件,所以它们在优化级别上不会改变。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-06-10 05:04:04

由于优化,strtod没有工作。多亏了@old_timer,我不得不创建自己的strtod函数,它甚至可以在2级设置的优化级别上工作。

代码语言:javascript
复制
double simple_strtod(const char* str)
{
 int8 inc;
 double result = 0.0;
 char * c_tmp;
 c_tmp = strchr(str, '.');
 if(c_tmp != NULL)
 {
    c_tmp++;
    inc = -1;
    while(*c_tmp != 0 && inc > -9)
    {
        result += (*c_tmp - '0') * pow(10.0, inc);
        c_tmp++; inc--;
    }
    inc = 0;
    c_tmp = strchr(str, '.');
    c_tmp--;
    do
    {
        result += (*c_tmp - '0') * pow(10.0,inc);
        c_tmp--; inc++;
    }while(c_tmp >= str);
 }
 return result; 
}

它可以进一步优化,不调用'pow‘,并使用更聪明的东西,但就像这样,它完美地工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44238420

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档