程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C說話main函數的參數及其前往值具體解析

C說話main函數的參數及其前往值具體解析

編輯:關於C++

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 

t void destroy0() throws LifecycleException; /* * @see * ILifecycle#addLifecycleListener(ILifecycleListener) */ @Override public void addLifecycleListener(ILifecycleListener listener) { listeners.add(listener); } /* * @see * ILifecycle#removeLifecycleListener(ILifecycleListener) */ @Override public void removeLifecycleListener(ILifecycleListener listener) { listeners.remove(listener); } private void fireLifecycleEvent(LifecycleEvent event) { for (Iterator<ILifecycleListener> it = listeners.iterator(); it.hasNext();) { ILifecycleListener listener = it.next(); listener.lifecycleEvent(event); } } protected synchronized LifecycleState getState() { return state; } private synchronized void setStateAndFireEvent(LifecycleState newState) throws LifecycleException { state = newState; fireLifecycleEvent(new LifecycleEvent(state)); } private String formatString(String pattern, Object... arguments) { return MessageFormat.format(pattern, arguments); } /* * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getSimpleName(); } }

可以看到,籠統類的骨架完成中做了幾件性命周期治理中通用的工作,檢討狀況之間的轉換能否正當(好比說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。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved