//=====================================================================
//TITLE:
// C++ VS C#(6):入口函數,改變形參數值
//AUTHOR:
// norains
//DATE:
// Wednesday 16-January-2011
//Environment:
// Visual Studio 2010
// Visual Studio 2005
//=====================================================================
1. 入口函數
入口函數是一個應用程序的執行時的入口點,當該函數執行完畢時,那麼該程序也就結束了。
對於C#來說,這個是一個很簡單的事情,入口函數就是Main,它有四種形式,如:
static void Main()
static void Main(string[] args)
static int Main()
static int Main(string[] args)
為什麼前面都帶有static修飾呢?因為C#是純粹的面向對象的語言,一切都包含在類之中,增加static標識是為了說明這是類的函數,而非成員函數。
而如果是C++,那麼情況就比較復雜了。如果是普通的C++程序,或DOS程序,那麼入口函數就是main。也就是說,形式如下:
int main()
int main(int argc,char *argv[])
看到這裡,熟悉C++的朋友可能會覺得奇怪了,C++沒有返回值為void的麼?如果嚴格根據C++98標准的話,標准裡確實只是寫了這兩個形式而已。可能有朋友又發問了,那為什麼我返回值為void的時候,還是能正常編譯通過呢?這個其實是和編譯器有關。比如,當返回值為void時,用VC6.0就能編譯通過,而g++3.2根本就無法通過。
編譯器的區別還不是麻煩的終點。如果你是在Windows環境下,那麼入口函數就不再是main,而是WinMain!是不是有點匪夷所思?同樣是C++程序,換了系統,居然連入口函數都改變了。但實際情況就是如此。
WinMain函數的形參比main函數多了兩個,並且形參還不能為空,其形式如下:
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
完了麼?如果你以為這已經是結束,那麼你太小看Windows下的C++了。因為隨著Windows從16bit到32bit的遷移,C++的入口函數也開始發生變化。在VC6.0裡,你可以使用WinMain,但如果是VS2005,並且編譯環境是UNICODE的話,那麼你需要使用的是:wWinMain!
理由很簡單,在ANSI環境,入口函數是WinMain;但在UNICODE環境,卻變成了wWinMain!能不能在代碼裡直接兼容這兩種環境呢?可以,但你需要將入口函數改為_tWinMain!
_tWinMain是什麼東西,有那麼大的威力?其實它只是一個宏,在TCHAR.h文件中定義:
//TCHAR.H
#ifdef _UNICODE
#define _tWinMain wWinMain
#else
#define _tWinMain WinMain
#endif
看到這,就明白為什麼能適應不同的編譯環境了吧?
2. 改變形參數值
在C++裡,如果想傳入形參的數值,那麼有什麼方法呢?方法有兩種,一個是指針,另一個是引用。
以例子來說明比較直接。我們需要一個函數,用來交換傳入形參的兩個數值。這是一個很簡單的例子,不是麼?
假設代碼中聲明了如下兩個變量:
int a = 10;
int b = 20;
采用引用方式的如下:
void Swap(int &a,int &b)
{
int tmp = a;
a = b;
b = tmp;
}
//直接傳入形參即可
Swap(a,b);
如果是指針的話,那麼也是很簡單的:
void Swap(int *pA,int *pB)
{
int tmp = *pA;
*pA = *pB;
*pB = tmp;
}
//調用時用&符號來表示這是指針
Swap(&a,&b);
引用和指針這兩種方式有什麼區別呢?如果是從功能的角度,沒有任何區別,它們都能夠完成交換的任務;而如果從哲學的角度,那麼采用指針的方式可以表明形參可以為NULL,而引用則表示形參絕對不能為NULL。這是不是有點玄乎?沒辦法,C++的復雜性就表現於此。與其說C++是一門語言,不如說其是一種信仰,一門哲學,可能更為恰當。如果簡單點來說,為何C++存在這兩種方式,追本溯源的話,其實是要和C兼容。引用是C++引進的新特性,在C裡面是沒有的。如果C要更改形參的數值,那麼就只能使用指針。為了兼容C,那麼C++肯定無可避免也存在著指針改變形參的方式。
但如果到了C#的話,因為取消了指針,所以它就只剩下引用這種模式。當然咯,C#的引用和C++的寫法是不同的,C++用&符號表示,而C#用的是ref關鍵字。而最大的區別還在於函數的調用,C++是直接輸入變量名,而C#則必須增加ref關鍵字。相應的代碼如下:
static void Swap(ref int a, ref int b)
{
int tmp = a;
a = b;
b = tmp;
}
//調用時必須帶有ref關鍵字
Swap(ref a,ref b);
初看起來,C#調用引用的時候需要增加ref關鍵字顯得略微繁瑣,其實在實際的使用過程中,這略微的繁瑣卻帶來更明晰的含義。比如,在C++中如果你僅僅是查看函數的調用:Swap(a,b),你能判斷得出a和b這兩個形參是否會被改變麼?因為無論是否引用,其調用方式都是一樣的,所以你必須要返回查看Swap的定義你才能確定。而這歧義在C#中根本就不存在,Swap(a,b)這語句絕對不會改變a和b的值;如果存在改變的可能,那麼必定使用ref標注,也就是Swap(ref a,ref b)的調用方式。