函数未声明引发的怪异现象
<p class="artical_littlestyle1">1.问题描述</p><p style="text-indent: 2em;">最近进行ARM嵌入式系统开发过程中遇到一个问题,就是打印浮点数据不正确。这里的打印函数在其他文件定义的,在main.c中调用了打印函数,但是并没有include打印函数的头文件,编译能够正确的编译过去,但是打印浮点数据时浮点数据的内容始终不正确,比如kprintf("float_num:%f\r\n", 12.06);实际显示的内容可能是:float_num:0.0000。</p><p style="text-indent: 2em;">最开始以为浮点的堆栈处理问题,后来检查浮点的入栈和出栈并没有什么问题,后来调试发现kprintf("float_num:%f\r\n", 12.06);这句代码的汇编格式使用d0在保存浮点数据,正常来说ARM传递参数使用的是r0,r1,r2,r3寄存器或者堆栈,这明显就不对,采用的貌似是编译器的通用参数处理方式。当然了导致这个问题的原因就是kprintf这个函数并未声明,因为kprintf函数未声明,编译器在编译当前文件时,并不知道kprintf函数的参数及顺序,因此采用的貌似是编译器的通用参数处理方式。</p><p style="text-indent: 2em;">kprintf函数未声明时,kprintf("float_num:%f\r\n", 12.06);对应的汇编代码为:</p><p><span style="color: rgb(0, 112, 192);">vldr d0, [pc, #188]</span></p><p><span style="color: rgb(0, 112, 192);">ldr r0, [pc, #200]</span></p><p><span style="color: rgb(0, 112, 192);">bl kprintf</span></p><p style="text-indent: 2em;">kprintf函数在main.c文件中声明了时,kprintf("float_num:%f\r\n", 12.06);对应的汇编代码为:</p><p><span style="color: rgb(0, 112, 192);">add r3, pc, #252</span></p><p><span style="color: rgb(0, 112, 192);">ldrd r2, r3, [r3]</span></p><p><span style="color: rgb(0, 112, 192);">ldr r0, [pc, #188]</span></p><p><span style="color: rgb(0, 112, 192);">bl kprintf</span></p><p style="text-indent: 2em;">函数未声明除了造成上述问题之外(参数传入的不正确导致结果出错),也可能导致结果正确,但是返回的结果不正确(比如一个函数返回double型的结果,如果函数未声明就使用,可能会返回4字节的结果,导致结果返回错误)。</p><p style="text-indent: 2em;">函数未声明时,kprintf("int_num:%d\r\n", 15);能够正确的显示,因为此时15这个值能够通过普通寄存器(r0/r1/r2/r3)传递,因此不会出现打印浮点数的问题。<span style="color: rgb(0, 112, 192);">如果传递的参数或者返回的值,不能通过普通寄存器(r0/r1/r2/r3)传递时,就可能出现奇怪的问题了。</span></p><p class="artical_littlestyle2">2.问题解决方法</p><p style="text-indent: 2em;">解决这个问题的方法自然是,在使用到kprintf的文件中include打印函数kprintf的头文件。</p><p class="artical_littlestyle3">3.小结</p><p style="text-indent: 2em;">对于开发过程中,如果编译时提示<span style="color: rgb(255, 0, 0);">"warning: implicit declaration of function 'xxx'"</span>这类的信息,<span style="color: rgb(255, 0, 0);">一定还是加上这些函数的声明</span>。如果不添加函数声明,编译虽然能够通过,但是遇到我上面提及的怪异问题,调试可能都不知如何下手,谨记吧。</p><p style="text-indent: 2em;">如果这篇文章对你有帮助,记得点赞和关注博主就行了^_^。</p>
暂无评论,要不要来个沙发
发表评论
JLink V9掉固件修复(灯不亮) 3Zephyr笔记2 - 在STM32F429上运行HelloWorld 2计算NandFlash要传入的行地址和列地址 1Linux MMC子系统 - 6.eMMC 5.1工作模式-设备识别模式 0Linux MMC子系统 - 5.eMMC 5.1工作模式-引导模式 0Linux MMC子系统 - 4.eMMC 5.1常用命令说明(2) 0
标签云
Linux嵌入式实用技巧ARM内核学习问题集合CC++编程语言阅读笔记汇编Linux内核完全注释Windows驱动开发计算机基础ARM11ARMv7-ASTM32IDESublimeLinux内核学习eMMCMMC子系统Ubuntu操作系统OfficeVMWareAPUEgccRTOS中断漫游世界随笔感悟开发工具软件应用编程VsCodearmccarmclang编译器ZephyrSPIJLink网卡驱动安装各种芯片库函数NFSμCOS内核sambaFlashUnix命令与脚本输入法Linux内核设计与实现gitRIFFWAVJATGFTPar8161安装centos有线上网μCGUI字库工程建立右键菜单网络文件系统Firefox百度NTFS文件系统CodeBlocksCentOS数据结构算法PhotoShop51KeilQTUltraEditscanfglibc宏定义UIDGID优先级娱乐天地SourceInsight磁盘扇区总线I2CPDFBComparePythonI2SFPUMakefileSWDCPUARP软件推荐FileZilla