今天這篇文章有點複雜,大家要注意一點看啦!
我們知道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住嗎!哈哈!