嵌入式C++開發詳解(一)
一、C++概述
1.嵌入式開發中為什么選擇C++語言?
(1)面向過程編程的特點
C語言特點:C語言是在實踐的過程中逐步完善的
·沒有深思熟慮的設計過程
·使用時存在很多“灰色地帶”
……
·殘留量過多低級語言的特征
·直接利用指針進行內存操作
……
面向過程的編程特點:
面向過程程序設計:數據結構+算法
·主要解決科學計算問題,用戶需求簡單固定
·特點:分析解決問題所需要的步驟
利用函數實現各個步驟
依次調用函數解決問題
·問題:軟件可重用性差
軟件可維護性差
構建的軟件無法滿足用戶需求
(2)面向對象編程的特點
面向對象的編程特點:
面向對象程序設計:由現實世界建立軟件模型
·將現實世界中的事物直接映射到程序中,可直接滿足用戶需求
·特點:直接分析用戶需求中涉及的各個實體
在代碼中描述現實世界中的實體
在代碼中關聯各個實體協同工作解決問題
·優勢:構建的軟件能夠適應用戶需求的不斷變化
直接利用面向過程方法的優勢而避開其劣勢
C++語言特點:高效的面向對象語言,并且能夠兼容已經存在的代碼

2.C++為什么難學?
C++支持的編程格式:
·過程式
·數據抽象
·基于對象
·面向對象式
·函數式
·泛型形式
·模板元形式
值語義和對象語義:
值語義可以拷貝與賦值,對象語義不可進行拷貝與賦值
3.C++相關基礎知識點
(1)C++之父是誰?
本賈尼·斯特勞斯特盧普
1982年,美國AT&T公司貝爾實驗室的Bjarne Stroustrup博士在c語言的基礎上引入并擴充 了面向對象的概念,發明了—種新的程序語言。為了表達該語言與c語言的淵源關系,它被命名為C++。而Bjarne Stroustrup(本賈尼·斯特勞斯特盧普)博士被尊稱為C++語言之父。
(2)C++語言的標準
C++ 98 標準
C++標準第一版,1998年發布。正式名稱為ISO/IEC 14882:1998[17] 。
C++ 03 標準
C++標準第二版,2003年發布。正式名稱為ISO/IEC 14882:2003[18] 。
C++ 11 標準
C++標準第三版,2011年8月12日發布。正式名稱為ISO/IEC 14882:2011[19] 。
C++11對容器類的方法做了三項主要修改。
首先,新增的右值引用使得能夠給容器提供移動語義。其次,由于新增了模板類initilizer_list,
因此新增了將initilizer_list作為參數的構造函數和賦值運算符。第三,新增的可變參數模板(variadic template)和函數參數包(parameter pack)使得可以提供就地創建(emplacement)方法。
C++ 14 標準
C++標準第四版,2014年8月18日發布。正式名稱為ISO/IEC 14882:2014[21] 。
C++14是C++11的增量更新,主要是支持普通函數的返回類型推演,泛型 lambda,擴
展的 lambda 捕獲,對 constexPR 函數限制的修訂,constexpr變量模板化等[22] 。
(3)C++11值得學習的新特性
·智能指針如shared_ptr、weak_ptr等
·rvalue reference
·function/bind
·lambda expression and closure
二、從C到C++的升級
1.聲明定義
C++:C++中更強調語言的實用性,所有變量都可以在需要使用時再定義
如:for(int i = 0; i < 2; i++)
C語言:變量必須在作用域開始時定義
2.register關鍵字的升級
經常被訪問的變量我們就可以用register修飾為寄存器變量,請求編譯器盡可能的將變量存在CPU的內部寄存器中,節省了CPU從內存中抓取數據的時間,從而提高了運行效率。
C語言:register只能修飾局部變量,不能修飾全局變量和函數;
register修飾的變量不能通過取地址來獲取寄存器變量;
register修飾的變量一定是CPU能接受的數據類型。
C++:在C++中依然支持register關鍵字
C++編譯器有自己的優化方式,不使用register中也可能做優化
C++中可以取register變量的地址(C++編譯器發現程序中需要取register
變量的地址時,register對變量聲明無效)
3.const關鍵字
C++:C++編譯器對const常量的處理
·當碰見常量聲明時在符號表中放入常量
·編譯過程中若發現使用常量則以符號表中的值替換
·編譯過程中若發現對const使用了extern或者&操作符,則給對應的常量
分配存儲空間
注意:C++編譯器雖然可能為const常量分配空間,但不會使用其存儲空間中
的值。
C語言:C語言中const修飾變量,空間里的值可變,但是不能通過變量名來修改這個空間的對應值。
4.內存分配與釋放
(1)C++中動態內存分配
·C++中通過new關鍵字進行動態內存申請
·C++的動態內存申請是基于類型進行的
·delete關鍵字用于內存釋放
變量申清:
Type *pointer = new Type;
……
delete pointer;
數組申清:
Type *pointer = new Type[];
……
delete[] pointer;
(2)new與malloc區別
·new關鍵字是C++的一部分,malloc是由C庫提供的函數
·new以具體類型為單位進行內存分配,malloc只能以字節為單位進行內存
分配
·new在申請單個類型變量時可進行初始化,malloc不具備內存初始化的特
性
5.引用VS指針
(1)引用
·引用是給一個變量起別名
·定義一個引用的一般格式:
·類型 &引用名 = 變量名
·例如:int a = 1;
int &b = a; //b是a的別名,因此a和b是同一個單元
注意:定義引用時一定要初始化,指明該引用變量是誰的別名
·在實際應用中,引用一般用作參數傳遞與返回值
(2)const引用是指向const對象的引用
(3)函數傳參:按引用傳遞
引用傳遞方式是在函數定義時在形參前面加上運算符“&”
例如:void swap(int &a,int &b);
·按值傳遞方式容易理解,但形參值得改變不能對實參產生影響
·地址傳遞方式通過形參的改變使響應的實參改變,但程序容易產生錯誤且難以閱讀
·引用作為參數對形參的任何操作都能改變相應的實參的數據,又使函數調用顯得方便、自然。
(4)函數返回值:引用作為函數返回值
·引用的另一個作用是用于返回引用的函數
·函數返回引用的一個主要目的是可以將函數放在賦值運算符的左邊
·注意:不能返回對局部變量的引用
(5)引用與指針的區別
·引用訪問一個變量是直接訪問,而指針是間接訪問
·引用是一個變量的別名,本身不單獨分配自己的內存空間,而指針有自己的內存空間
·引用一經初始化不能再引用其它變量,而指針可以
·盡可能使用引用,不得已時使用指針
6.函數升級
(1)內聯函數(inline):以空間換時間(頻繁調用且簡短)
內聯函數的使用:
inline int max(int a,int b)
{
return a>b?a:b;
}
#define MAX(a,b) (a)>(b)?(a):(b)
內聯函數與帶參數宏的區別:
·內聯函數調用時,要求實參和形參的類型一致,另外內聯函數會先對實
參表達式進行求值,然后傳遞給形參;而宏調用只用實參簡單地替換形
參。
·內聯函數是在編譯的時候、在調用的時候將代碼展開的,而宏則是在預
處理時進行替換的
·在C++中建議有用inline函數來替換帶參數的宏
(2)函數重載(overload)
相同的作用域,如果兩個函數名稱相同,而參數不同,我們把它們稱為重載overload
函數重載的條件:(函數的返回值不能作為條件)
·函數重載不同形式:
·形參數量不同
·形參類型不同
·形參順序不同
·形參數量和形參類型都不同
·調用重載函數時,編譯器通過檢查參數的個數、類型和順序來確定相應
的被調用函數
name managling與extern “C”:
·name managling 這里把它翻譯為名字改編
·C++為了支持重載,需要進行name managling
·extern“C”實現了C與C++混合編程
#ifdef__cpluscplus
extern“C”
{
#endif
……
#ifdef__cpluscplus
}
#endif
(3)帶默認參數的函數:
·函數沒有聲明時,在函數定義中指定形參的默認值
·函數既有定義又有聲明時,聲明時指定后,定義后就不能再指定默認值
·默認值的定義必須遵守從右到左的順序,如果某個形參沒有默認值,則
它左邊的參數就不能有默認值
void funcl(int a,double b = 4.5,int c = 3) //合法
void funcl(int a = 1,double b ,int c = 3) //不合法
·函數調用時,實參與形參按從左到右的順序進行匹配
7.命名空間-namespace
(1)命名空間
·在C語言中只有一個全局作用域
·C語言中所有的全局標識符共享一個作用域
·標識符之間可能有沖突
·C++中提出了命名空間的概念
·命名空間將全局作用域分成不同的部分
·不同命名空間中的標識符可以同名而不會發生沖突
·命名空間可以相互嵌套
·全局作用域也叫默認命名空間
(2)如何定義命名空間
namespace First
{
int i = 0;
}
namespace Second
{
int i = 1;
}
using namespace First;
int main()
{
cout<<i<<endl;
cout<<Second::i<<endl;
return 0;
}
(3)如何使用命名空間
·使用整個命名空間:using namespace name;
·使用命名空間中的變量:using name::variable;
·使用默認命名空間中的變量: ::variable
默認情況下可以直接使用
默認命名空間中的所有標識符
8.新的類型轉換運算符
(1)static_cast<T>(expr)
·用于基本類型間的轉換,但不能用于基本類型指針間的轉換
·用于有繼承關系類對象之間的轉換和類指針之間的轉換
int main()
{
int i = 0;
char c = ‘c’;
int *pi = &i;
char *pc = &c;
c = static_cast<char>(i);//success
pc = static_cast<char *>(pi);//error
return 0;
}
static_cast是在編譯期進行轉換的,無法在運行時檢測類型,所以類類型之間的轉換可能存在風險
(2)const_cast<T>(expr)
const_cast強制類型轉換——用于去除變量的const屬性
int main()
{
const int &j = 1;
int & k = const_cast<int&>(j);
const int x = 2;
int & y = const_cast<int&>(x);
k = 5;
cout << j << endl;
cout << k << endl;
y = 3;
cout <<x<<endl;
cout<<y<<endl;
cout <<&x<<endl;
cout<<&y<<endl;
return 0;
}
(3)reinterpret_cast<T>(expr)
reinterpret_cast強制類型轉換
·用于指針類型間的強制轉換
·用于整數和指針類型間的強制轉換
typedef void(pf)(int)
int main()
{
int i = 0;
char c = ‘c’;
int * pi = reinterpret_cast<int *>(&c);
char * pc = reinterpret_cast<char *>(&i);
PF * pf = reinterpret_cast<PF*>(0x12345678);
c = reinterpret_cast<char>(i);
return 0;
}
reinterpret_cast直接從二進制位進行賦值,是一種極其不安全的轉換。
(4)dynamic_cast<T>(expr)
dynamic_cast強制類型轉換
·主要用于類層次間的轉換,還可以用于類之間的交叉轉移
·dynamic_cast還具有類型檢查的功能,比static_cast更安全
新聞熱點
疑難解答
圖片精選