//=====================================================================
//TITLE:
// C++ VS C#(6):入口函数,改变形参数值
//AUTHOR:
// norains
//DATE:
// Wednesday 16-January-2011
//Environment:
// Visual Studio 2010
// Visual Studio 2005
//=====================================================================
1.入口函数
入口函数是一个应用程序的执行时的入口点,当该函数执行完毕时,那么该程序也就结束了。
对于C#来说,这个是一个很简单的事情,入口函数就是Main,它有四种形式,如:
为什么前面都带有static修饰呢?因为C#是纯粹的面向对象的语言,一切都包含在类之中,增加static标识是为了说明这是类的函数,而非成员函数。
而如果是C++,那么情况就比较复杂了。如果是普通的C++程序,或DOS程序,那么入口函数就是main。也就是说,形式如下:
看到这里,熟悉C++的朋友可能会觉得奇怪了,C++没有返回值为void的么?如果严格根据C++98标准的话,标准里确实只是写了这两个形式而已。可能有朋友又发问了,那为什么我返回值为void的时候,还是能正常编译通过呢?这个其实是和编译器有关。比如,当返回值为void时,用VC6.0就能编译通过,而g++3.2根本就无法通过。
编译器的区别还不是麻烦的终点。如果你是在Windows环境下,那么入口函数就不再是main,而是WinMain!是不是有点匪夷所思?同样是C++程序,换了系统,居然连入口函数都改变了。但实际情况就是如此。
WinMain函数的形参比main函数多了两个,并且形参还不能为空,其形式如下:
完了么?如果你以为这已经是结束,那么你太小看Windows下的C++了。因为随着Windows从16bit到32bit的迁移,C++的入口函数也开始发生变化。在VC6.0里,你可以使用WinMain,但如果是VS2005,并且编译环境是UNICODE的话,那么你需要使用的是:wWinMain!
理由很简单,在ANSI环境,入口函数是WinMain;但在UNICODE环境,却变成了wWinMain!能不能在代码里直接兼容这两种环境呢?可以,但你需要将入口函数改为_tWinMain!
_tWinMain是什么东西,有那么大的威力?其实它只是一个宏,在TCHAR.h文件中定义:
看到这,就明白为什么能适应不同的编译环境了吧?
2.改变形参数值
在C++里,如果想传入形参的数值,那么有什么方法呢?方法有两种,一个是指针,另一个是引用。
以例子来说明比较直接。我们需要一个函数,用来交换传入形参的两个数值。这是一个很简单的例子,不是么?
假设代码中声明了如下两个变量:
采用引用方式的如下:
如果是指针的话,那么也是很简单的:
引用和指针这两种方式有什么区别呢?如果是从功能的角度,没有任何区别,它们都能够完成交换的任务;而如果从哲学的角度,那么采用指针的方式可以表明形参可以为NULL,而引用则表示形参绝对不能为NULL。这是不是有点玄乎?没办法,C++的复杂性就表现于此。与其说C++是一门语言,不如说其是一种信仰,一门哲学,可能更为恰当。如果简单点来说,为何C++存在这两种方式,追本溯源的话,其实是要和C兼容。引用是C++引进的新特性,在C里面是没有的。如果C要更改形参的数值,那么就只能使用指针。为了兼容C,那么C++肯定无可避免也存在着指针改变形参的方式。
但如果到了C#的话,因为取消了指针,所以它就只剩下引用这种模式。当然咯,C#的引用和C++的写法是不同的,C++用&符号表示,而C#用的是ref关键字。而最大的区别还在于函数的调用,C++是直接输入变量名,而C#则必须增加ref关键字。相应的代码如下:
初看起来,C#调用引用的时候需要增加ref关键字显得略微繁琐,其实在实际的使用过程中,这略微的繁琐却带来更明晰的含义。比如,在C++中如果你仅仅是查看函数的调用:Swap(a,b),你能判断得出a和b这两个形参是否会被改变么?因为无论是否引用,其调用方式都是一样的,所以你必须要返回查看Swap的定义你才能确定。而这歧义在C#中根本就不存在,Swap(a,b)这语句绝对不会改变a和b的值;如果存在改变的可能,那么必定使用ref标注,也就是Swap(ref a,ref b)的调用方式。