【分享帖】用C++11开发STM32程序
5030
0
30
2017-12-14
今天这篇文章有点复杂,大家要注意一点看啦!
我们知道KEIL是支持C++的,网上一搜索也能找到一些使用C++的方法,无非是在Keil里的options->C/C++->Misc Controls里添加—cpp,如果要支持c++11,还需要指定—cpp11。事实上这样的C++并不是完整意义的上的C++,本人测试过,有好多C++的新功能都是没有办法实现的。这里需要注明的是,在KEIL5.18a以前的版本(包括5.18a)所支持的Arm Compiler只有ARM Compiler 5以及更低的版本,C++11支持不完整,而对C++11有完整支持就必须要使用Arm Compiler 6 即 AC6。
为了使用对C++11有完整支持的Arm Compiler 6(AC6),今天所使用的KEIL MDK版本至少应用为5.20版本以上(Arm Compiler 6.4)
本文中本人使用的AC6为6.7版本,为KEIL MDK 4.24a所自带的AC6编译器
这里需要注意的是AC6仅支持以下系统
- Windows Server 2012, 64-bit only.
- Windows 7 Enterprise SP1.
- Windows 7 Professional SP1.
- Windows 8.1, 64-bit only.
- Windows 10, 64-bit only.
所以大家在试验之前,一定要检查下自己所使用的环境,否则就会浪费时间啦。
关于MDK的下载以及和谐办法,大家自行百度解决啦~
在开始之前,有个东西要了解,那就是microlib,不知道大家知道不知道,本来想写一篇关于microlib的文章,想必这是大家最熟悉的陌生人了。使用STM32CubeMX生成的MDK工程都会自动链接这个系统自带的库。
它就是Code Generation里的Use MicroLIB,默默地被勾上。
那么他最主要的作用是什么呢?
- 创建栈空间
- 创建堆空间,如果需要的话,这样才可以使用malloc等一些函数
- 初始化用户可能用到的系统库
- 调用用户的main函数
- Microlib不支持exit函数
如果是C/C++ standardlib 还支持
- 支持应用程序使用ISO定义的函数
- 可以捕捉运行时错误并发送信号,如果需要,在错误发生时或行程序退出时还可以停止运行
然而真正的C++开发是不能链接microlib的,因为他只是标准C library的一个精简集。网上能查到microlib的一些限制,这里列举一些出来
- Microlib和标准的IOS C库不兼容,所以不支持有些ISO所提供的特性或者功能不完整
- 仅对C99库提供有限的函数支持
- Microlib不支持C++
- 不支持位置独立的代码
- 不支持单个或双个的内存区域模型
- 不支持Mutex以及不支持宽字符
正常情况下,在STM32CubeMX通过成的.s文件里可以看到一个__main函数,这个就是microlib的入口地址,他会完成上述的初始化动作,最后跳转到我们熟悉的main。
刚才也说过我们要实现真正的C++编程,就不能链接microlib,如果不链接microlib,就会默认链接到我们的C/C++标准库。
现在开始,首先依然是使用STM32CubeMX生成一个带串口的工程,阿圆有依旧是STM32F437ZGT6,工程名为ARMCCTest,要使用完整的C++11特性就必须使用AC6,这里把ARM Compiler设置为V6.7,并勾掉Use MicroLib
这里根据ARM官方的建议,检查下Short enums/wchar是否勾上
这样就设置好了。
但是呢,如果就这样去编译,会有一堆的编译错误
主要是__weak编译失败
AC6己经不支持直接声明 __weak了,需要使用 __attribute__((weak))替代。这里不建议使用全局替代的方法, 如下图所示
因为如果你的的工程里有包含了C++文件,这种方法可能把系统库里的__weak也给替换了,曾经吃过大亏!结果都重装KEIL了
好的,为了测试C++11的功能,我们新建一个CppTest.cpp文件,为了保持和C的兼容性呢我们把main挪到了cpp文件里,将原来Keil生成的main改为cmain即可
这里看到有一个Test类,这就是我们需要对C++11特性进行测试的类
这里面还包含了一个Base和Derived类
这样一个简单的C++测试用例就写好了!
但是!这样是不能执行的!一旦执行系统在跳到__main时之后就跑飞了!
大家可以想一想这是怎么一回事?
留白
留白
留白
好啦,不卖关子啦,事实上本人也找了近两天的时间才找到解决办法,一开始认为是heap和stack没有初始化好,尝试了好久均未成功,后来在网上得到启发,这个问题是出在STDIO初始化上。
如果要使用C/C++标准库就要对其STDIO进行Retarget的,很简单,但却是非常关键的一步,就是这么一回事啦。
下载ARM官方的retarget文件,并加入到工程当中
下载链接
http://infocenter.arm.com/help/topic/com.arm.doc.faqs/attached/3844/retarget.c
稍微进行小修改,把它重定向到串口就可以啦!
现在就可以把代码编译运行一下,从SSCOM看到代码正常运行并输出了log
都运行成功了!
要问为什么没有使用std::cout,我也觉得很奇怪啦
../Src/CppTest.cpp(44): error: no member named 'cout' in namespace 'std'std::cout<< "adsaf" ;~~~~~^
上面只是简单测试了C++ vector容器,智能指针,auto变量和lambda表达式,当然C++11的内容比这要广泛得多,大家可自行测试!
不过要使用上完整的C++11代价也是非常大的(未开启优化 -O0编译)!上面的代码几乎不做什么有用的功能其大小竟然达到了可怕的231K!
大家还Hold住吗!哈哈!
文章标签
请问这篇文章对你有用吗?
【分享帖】用C++11开发STM32程序