C與C++的區別(上)
一、函式的預設值
int sum(int a,int b)
{
return a+b;
}
int main()
{
int a = 10;
int b = 20;
sum(a,b);
}
以上程式碼sum(a,b)的反彙編為
00C3144C mov eax,dword ptr [b]
00C3144F push eax
00C31450 mov ecx,dword ptr [a]
00C31453 push ecx
00C31454 call sum (0C3105Fh)
00C31459 add esp,8
如果將sum函式設定預設值,即
int sum(int a,int b = 20)
{
return a+b;
}
int main()
{
int a = 10;
sum(a);
//sum(a,30);30為立即數
}
以上程式碼sum函式的反彙編為
00231445 push 14h
00231447 mov eax,dword ptr [a]
0023144A push eax
0023144B call sum (023105Fh)
00231450 add esp,8
與未初始化的函式相比就少了一步mov b的過程。
預設值的總結:
預設值是從右往左賦值的,絕不可以int sum(int a = 10,int b);
但是在函式宣告的時候可以這樣寫:
int sum(int a,int b=20);
int sum(int a=10,int b);
這是因為在前一行的sum函式中已經給b賦值了
但是如果將以上兩句函式宣告倒過來寫,將原來的第一句放在第二句的位置,就不行了,因為編譯器是從上往下編譯的,原來的第二句並沒有給b先賦值。
二、inline行內函數
1、在呼叫點把程式碼直接展開(不會給sum函式開闢棧,而是直接的替換。)
例:
inline int sum(int a,int b)
{
return a+b;
}
int main()
{
int ret = sum(10,20);//將此句直接轉換為:ret = 10+20
}
2、巨集(#define)和行內函數(inline)的區別
巨集:處於預編譯階段,不會做的詞法解析以及型別檢查,出錯的可能性高,不安全。
下面舉一個例子:
#define Max(a,b) a>b?a:b
int main()
{
int a = Max(10,20)+20;
printf("%d\n",a);
return 0;
}
上面這段程式碼輸出的會是什麼呢?
輸出的是:40
為什麼呢?
上面說過了,巨集定義就是字元替換,所以原函式中的a = Max(10,20)+20就變為了a = 10>20?10:(20+20)。
行內函數:處於編譯階段,有進行詞法解析以及型別檢查,只要有錯誤就會編譯失敗,所以說inline函式是安全的。
3、行內函數和普通函式的區別
普通函式:需要開闢棧幀,清理棧幀(棧的回退)。
行內函數:沒有棧幀的開闢及回退。
4、行內函數和static函式的區別
static函式:生成符號、符號屬性;需要開闢棧幀,清理棧幀(棧的回退)。
行內函數:不產生符號;沒有棧幀的開闢及回退。
static和inline函式的相同點:都只能在當前檔案中使用。
另:普通函式與static函式的區別:普通函式中的變數是global全域性變數,static函式中的是local區域性變數。
Q:我們在什麼時候用行內函數呢?
A:在棧幀開闢的開銷(函式呼叫的開銷)>函式執行的開銷時。
最後需要注意的是:1、inline函式只在release版本中生效,在debug版本中的inline函式的呼叫也需要棧幀的開闢和回退。
2、inline函式只是對編譯器的一個建議,最終能不能起作用是由編譯器來決定的。比如:inline函式對遞迴函式不起作用,因為不知道需要展開函式幾次。
三、函式的過載
c語言:函式產生符號由函式名稱決定,所以函式的定義不能重名,否則出現重定義。
C++:函式產生符號由函式名稱+形參的型別+形參的個數決定。函式定義可以重名,但前提是函式的引數不能完全相同。
例如:
bool compare(int a,int b)
{
cout<<"compare(int,int)"<<endl;
return a>b;
}
bool compare(double a,double b)
{
cout<<"compare(double,double)"<<endl;
return a>b;
}
bool compare(char* a,char* b)
{
cout<<"compare(char*,char*)"<<endl;
return strcmp(a,b)>0?true:false;
}
int main()
{
compare(10,20);
compare(10.5,20.6);
compare("hello","world");
return 0;
}
上方的函式在C語言中不能編譯成功,因為函式重定義了。
而在C++中,三個函式名稱分別為:compare_int_int;compare_double_double;compare_char*_char*
所以,1、我們把函式名相同,引數列表不同的函式稱為一組過載函式。2、過載必須處於同一個作用域中。例:如果在主函式中加入一行函式宣告
int main()
{
compare(int a,int b);
compare(10,20);
compare(10.5,20.6);
compare("hello","world");
return 0;
}
再編譯時就會出現型別無法轉換的情況。
如果將以上程式碼改為
bool compare(int a,int b)
{
cout<<"compare(int,int)"<<endl;
return a>b;
}
bool compare(float a,float b)
{
cout<<"compare(float,float)"<<endl;
return a>b;
}
bool compare(char* a,char* b)
{
cout<<"compare(char*,char*)"<<endl;
return strcmp(a,b)>0?true:false;
}
int main()
{
compare(10,20);
compare(10.5,20.6);
compare("hello","world");
return 0;
}
編譯時就會出錯,不知將10.5和20.6轉換為int還是double型別。
箭頭所指的線路都是編譯器預設會選擇的優先轉向。
比如short型別參與運算時,都會預設轉換成int型計算,最後再將結果轉化為short,這樣做是為了提高精度。
為了更好的理解,下面舉出一個例子:
unsigned int a = 1;
char b = -1;
char c = a>b?'a':'b';//b
cout<<c<<endl;
unsigned short a = 1;
char b = -1;
char c = a>b?'a':'b';//a
cout<<c<<endl;
四、C與C++的相互呼叫
1、C++轉C(看得見原始碼)
2.1、C轉C++
2.2、C轉C++(看不見原始碼)