C說話main函數的參數及其前往值具體解析。本站提示廣大學習愛好者:(C說話main函數的參數及其前往值具體解析)文章只能為提供參考,不一定能成為您想要的結果。以下是C說話main函數的參數及其前往值具體解析正文
前往值的感化
main函數的前往值用於解釋法式的加入狀況。假如前往0,則代表法式正常加入;前往其它數字的寄義則由體系決議。平日,前往非零代表法式異常加入。上面我們在winxp情況下做一個小試驗。起首編譯上面的法式:
int main( void )
{
return 0;
}
然後翻開附件裡的“敕令提醒符”,在敕令行裡運轉適才編譯好的可履行文件,然後輸出“echo%ERRORLEVEL%”,回車,便可以看到法式的前往值為0。假定適才編譯好的文件是a.exe,假如輸出“a && dir”,則會列出以後目次下的文件夾和文件。然則假如改成“return -1”,或許其余非0值,從新編譯後輸出“a && dir”,則dir不會履行。由於&&的寄義是:假如&&後面的法式正常加入,則持續履行&&前面的法式,不然不履行。也就是說,應用法式的前往值,我們可以掌握要不要履行下一個法式。這就是int main的利益。假如你有興致,也能夠把main函數的前往值類型改成非int類型(如float),從新編譯後履行“a && dir”,看看會湧現甚麼情形,想一想為何會湧現那樣的情形。趁便提一下,假如輸出a || dir的話,則表現假如a異常加入,則履行dir。
----------------------朋分線--------------------
經由過程操作體系來看前往值是通用方法
不外也能夠經由過程法式本身顯示
法式代碼以下 (只用到尺度C外面的內容)
#include
#include
int code;
void my_exit (void)
{
printf ("retrun value is %d\n", code);
}
int main (void)
{
atexit (my_exit);
return code = 0; //或許其他的前往值 由於code = 0表達式的成果是code的值 然後把這個值傳給 return 所以跟return 0是一樣的後果 只是多了個附感化就是給code賦值 好輸入
}
不要認為這裡和直接打印0有甚麼差別
本身看atexit函數 是干甚麼吧 對你進修main也有贊助的
----------------------朋分線--------------------
只是純真舉個例子,遞歸挪用main的例子,沒有現實意義
int num=3;//全局變量
int main()
{
num--;
int i=10;
if(num>=0)
int i=main();//遞歸挪用main()
return 0;
}
設置斷點今後調試可以看到i值的變更情形
在非遞歸挪用main()的法式中,exit(0)和return 0;的用處是一樣的,然則在遞歸挪用main的法式中,exit(0)可以停止法式,而return 0;是停止以後main函數
----------------------朋分線--------------------
第二部門:C說話之Main函數前往值成績剖析
許多人乃至市情上的一些書本,都應用了void main( ) ,其實這是毛病的。C/C++ 中歷來沒有界說過void main( )。C++ 之父 Bjarne Stroustrup 在他的主頁上的 FAQ 中明白地寫著 The definition void main( ) { }is not and never has been C++, nor has it even been C.( void main( ) 歷來就不存在於C++ 或許 C )。上面我分離說一下 C 和 C++ 尺度中對 main 函數的界說。
“The C programming Language(《C 法式設計說話》)用的就是 main( )。”--- 這是由於初版的C說話只要一品種型,那就是int,沒有char,沒有long,沒有float,…………既然只要一品種型,那末便可以不寫,後來的改良版為了兼容之前的代碼因而劃定:不明白標明前往值的,默許前往值為int,也就是說 main()同等於int main(),而不是同等於void main()。在C99中,尺度請求編譯器至多給 main() 這類用法來個正告。
1. C
在 C89 中,main( ) 是可以接收的。Brian W. Kernighan 和 Dennis M. Ritchie 的經典巨著 The C
programming Language 2e(《C 法式設計說話第二版》)用的就是 main( )。不外在最新的 C99 尺度中,只要以下兩種界說方法是准確的:
int main( void )
int main( int argc, char *argv[] )
(參考材料:ISO/IEC 9899:1999 (E) Programming languages — C 5.1.2.2.1 Program startup)
固然,我們也能夠做一點小小的修改。例如:char *argv[] 可以寫成 char **argv;argv 和 argc 可以改成其余變量名(如 intval 和 charval),不外必定要相符變量的定名規矩。
假如不須要從敕令行中獲得參數,請用int main(void) ;不然請用int main( int argc, char *argv[] )。
main 函數的前往值類型必需是 int ,如許前往值能力傳遞給法式的激活者(如操作體系)。
假如 main 函數的最初沒有寫 return 語句的話,C99 劃定編譯器要主動在生成的目的文件中(如 exe 文件)參加return 0; ,表現法式正常加入。不外,我照樣建議你最好在main函數的最初加上return 語句,固然沒有這個需要,但這是一個好的習氣。留意,vc6不會在目的文件中參加return 0; ,年夜概是由於 vc6 是 98 年的產物,所以才不支撐這個特征。如今明確我為何建議你最好加上 return 語句了吧!不外,gcc3.2(Linux 下的 C 編譯器)會在生成的目的文件中參加 return 0; 。
2. C++
C++98 中界說了以下兩種 main 函數的界說方法:
int main( )
int main( int argc, char *argv[] )
(參考材料:ISO/IEC 14882(1998-9-01)Programming languages — C++ 3.6 Start and termination)
int main( ) 同等於 C99 中的 int main( void ) ;int main( int argc, char *argv[] ) 的用法也和C99 中界說的一樣。異樣,main 函數的前往值類型也必需是int。假如main函數的末尾沒寫return語句,C++98 劃定編譯器要主動在生成的目的文件中參加 return 0; 。異樣,vc6 也不支撐這個特征,然則 g++3.2(Linux 下的 C++編譯器)支撐。
3. 關於 void main
在 C 和 C++ 中,不吸收任何參數也不前往任何信息的函數原型為“void foo(void);”。能夠恰是由於這個,所以許多人都誤以為假如不須要法式前往值時可以把main函數界說成void main(void) 。但是這是毛病的!main函數的前往值應當界說為 int 類型,C 和 C++ 尺度中都是如許劃定的。固然在一些編譯器中,void main 可以經由過程編譯(如 vc6),但並不是一切編譯器都支撐 void main ,由於尺度中歷來沒有界說過 void main 。g++3.2 中假如main 函數的前往值不是 int 類型,就基本通不外編譯。而 gcc3.2 則會收回正告。所以,假如你想你的法式具有很好的可移植性,請必定要用 int main .
--------------------------------------------------
總而言之:
void main 主函數沒有前往值
main 默許為int 型,即 int main(), 前往整數。
留意,新尺度不許可應用默許前往值,即int不克不及省,並且對應main函數不再支撐void型前往值,是以為了使法式有很好的移植性,激烈建議應用:
int main()
{
return 0;
}
--------------------------------------------------------------------------
第三部門:關於main(int argc, char *argv[])
以下摘錄一小段:
argc是敕令行總的參數個數
argv[]是argc個參數,個中第0個參數是法式的全名,今後的參數
敕令行前面跟的用戶輸出的參數,好比:
int main(int argc, char* argv[])
{
int i;
for (i = 0; i<argc; i++)
cout<<argv[i]<<endl;
cin>>i;
return 0;
}
履行時敲入
F:\MYDOCU~1\TEMPCODE\D1\DEBUG\D1.EXE aaaa bbb ccc ddd
輸入以下:
F:\MYDOCU~1\TEMPCODE\D1\DEBUG\D1.EXE
aaaa
ccc
ddd
可以看到,籠統類的骨架完成中做了幾件性命周期治理中通用的工作,檢討狀況之間的轉換能否正當(好比說start之前必需要init),設置外部狀況,和觸發響應的監聽者。
籠統類完成了ILifeCycle界說的辦法後,又留出了響應的籠統辦法供其子類完成,如下面的代碼所示,其留出來的籠統辦法有以下這些:
protected abstract void init0() throws LifecycleException; protected abstract void start0() throws LifecycleException; protected abstract void suspend0() throws LifecycleException; protected abstract void resume0() throws LifecycleException; protected abstract void destroy0() throws LifecycleException;
優雅的完成
到今朝為止,我們曾經界說了接口ILifeCycle,和其骨架完成AbstractLifeCycle,而且增長了監聽者機制。貌似我們可以開端寫一個類來繼續AbstractLifecycle,偏重寫其界說的籠統辦法了,so far so good。
但在開端之前,我們還須要斟酌別的幾個成績,
我們的完成類能否對一切的籠統辦法都感興致?
能否每一個完成累都須要完成init0, start0, suspend0, resume0, destroy0?
能否有時刻,我們的那些有性命的類或許模塊其實不支撐暫停(suspend),恢復(resume)?
直接繼續AbstractLifeCycle,就意味著必需完成其全體的籠統辦法。
是以,我們還須要一個默許完成,DefaultLifeCycle,讓它繼續AbstractLifeCycle,並完成一切籠統辦法,但它其實不做任何現實的工作, do nothing。只是讓我們真實的完成類來繼續這個默許的完成類,偏重寫感興致的辦法。
因而,我們的DefaultLifeCycle就這麼出生了:
public class DefaultLifecycle extends AbstractLifecycle { /* * @see AbstractLifecycle#init0() */ @Override protected void init0() throws LifecycleException { // do nothing } /* * @see AbstractLifecycle#start0() */ @Override protected void start0() throws LifecycleException { // do nothing } /* * @see AbstractLifecycle#suspend0() */ @Override protected void suspendInternal() throws LifecycleException { // do nothing } /* * @see AbstractLifecycle#resume0() */ @Override protected void resume0() throws LifecycleException { // do nothing } /* * @see AbstractLifecycle#destroy0() */ @Override protected void destroy0() throws LifecycleException { // do nothing } }
關於DefaultLifeCycle來講,do nothing就是其職責。
是以接上去我們可以寫一個本身的完成類,繼續DefaultLifeCycle,偏重寫那些感興致的性命周期辦法。
例如,我有一個類只須要在初始化,啟動,和燒毀時做一些義務,那末可以這麼寫:
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class SocketServer extends DefaultLifecycle { private ServerSocket acceptor = null; private int port = 9527; /* * @see DefaultLifecycle#init0() */ @Override protected void init0() throws LifecycleException { try { acceptor = new ServerSocket(port); } catch (IOException e) { throw new LifecycleException(e); } } /* * @see DefaultLifecycle#start0() */ @Override protected void start0() throws LifecycleException { Socket socket = null; try { socket = acceptor.accept(); //do something with socket } catch (IOException e) { throw new LifecycleException(e); } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /* * @see DefaultLifecycle#destroy0() */ @Override protected void destroy0() throws LifecycleException { if (acceptor != null) { try { acceptor.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
這裡的ServerSocket中,init0初始化socket監聽,start0開端獲得socket銜接, destroy0燒毀socket監聽。
在這套性命周期治理機制下,我們將會很輕易地對資本停止治理,不會產生資本未封閉的情形,架構和模塊化加倍清楚。
序幕
到這裡為止,本文曾經完成了一個簡略單純的性命周期治理機制,並給出一切的完成代碼。以後會將一切源代碼放到github上。請存眷本文的update。