所有 C++ 程式都必須有 main 函式。 如果您嘗試在沒有 main 函式的情況下編譯 C++ 程式,編譯程式會引發錯誤。 (動態連結程式庫和 static 連結程式庫沒有 main 函式。) main 函式是原始程式碼開始執行的位置,但在程式進入 main 函式之前,沒有明確初始化運算式的所有 static 類別成員都會設定為零。 在 Microsoft C++ 中,全域 static 物件也會在進入 main 之前初始化。 數項限制會套用到不適用於任何其他 C++ 函式的 main 函式。
main 函式:
- 無法過載 (請參閱函式過載) 。
- 無法宣告為
inline。 - 無法宣告為
static。 - 無法取得自己的位址。
- 無法從您的程式呼叫。
main 函式簽章
main 函式沒有宣告,因為該函式內建於語言中。 如果這樣做,main 的宣告語法看起來會像這樣:
int main();
int main(int argc, char *argv[]);
如果未在 main 中指定任何傳回值,編譯程式會提供零的傳回值。
標準命令列引數
main 的引數允許方便的命令行剖析引數。
argc 和 argv 的類型是由語言定義。
argc 和 argv 是傳統的名稱,但您可以將其命名為任何喜歡的名稱。
引數定義如下:
argc
包含 argv 之後引數計數的整數。
argc 參數永遠會大於或等於 1。
argv
以 null 終止之字串的陣列,表示由程式的使用者所輸入的命令列引數。 依照慣例,argv[0] 是對程式叫用的命令。
argv[1] 是第一個命令列引數。 來自命令列的最後一個引數是 argv[argc - 1],而 argv[argc] 一定是 NULL。
如需如何隱藏命令行處理的資訊,請參閱自定義 C++ 命令行處理。
注意
依照慣例,argv[0] 是程式的檔名。 不過在 Windows 上,您可以使用 CreateProcess 來繁衍流程。 如果您使用第一個和第二個引數 (lpApplicationName 和 lpCommandLine) ,argv[0] 可能不是可執行檔名稱。 您可以使用 GetModuleFileName 來擷取可執行文件名稱及其完整路徑。
專屬於 Microsoft 的擴展
以下部分介紹專屬於 Microsoft 的行為。
wmain 函式和 _tmain 巨集
如果您將原始程式碼設計為使用 Unicode 寬字元,您可以使用 Microsoft 專屬 wmain 進入點,這是 main 的寬字元版本。 以下是 wmain 的有效宣告語法:
int wmain();
int wmain(int argc, wchar_t *argv[]);
您也可以使用 Microsoft 專屬的 _tmain,這是 tchar.h 中定義的預處理器巨集。 除非已定義 _tmain,否則 main 會解析為 _UNICODE。 在此情況下,_tmain 會解析成 wmain。
_tmain 巨集和開頭為 _t 的其他巨集對於必須針對窄字元集和寬字元集建置個別版本的程式碼很有用。 如需詳細資訊,請參閱使用泛型文字對應。
從 void 回到 main
做為 Microsoft 延伸模組,main 和 wmain 函式可以宣告為傳回 void (沒有傳回值) 。 其他編譯程式也提供此延伸模組,但不建議使用。 當 main 未傳回值時,就可用於對稱。
如果您宣告 main 或 wmain 傳回 void,則無法使用 exit 陳述式,將 return 程式碼傳回至父流程或作業系統。 若要在 exit 或 main 宣告為 wmain 時傳回 void 程式碼,您必須使用 exit 函式。
envp 命令列引數
main 或 wmain 簽章允許選擇性的 Microsoft 專屬延伸模組存取環境變數。 此延伸模組也適用於 Windows 和 UNIX 系統的其他編譯程式。
envp 為傳統名稱,但您可以命名環境參數。 以下是包含環境參數之引數清單的有效宣告:
int main(int argc, char* argv[], char* envp[]);
int wmain(int argc, wchar_t* argv[], wchar_t* envp[]);
envp
選用的 envp 參數是一個字串的陣列,表示在使用者的環境中設定的變數。 這個陣列由 NULL 項目終止。 此陣列可以宣告為 char 的指標陣列 (char *envp[]),或是宣告為 char 指標的指標 (char **envp)。 如果您的應用程式使用 wmain 而非 main,請使用 wchar_t 資料類型,而不是 char。
傳遞至 main 和 wmain 的環境區塊是目前環境的「凍結」複本。 如果您之後透過呼叫 putenv 或 _wputenv 變更環境,則目前環境 (如 getenv 或 _wgetenv 和 _environ 或 _wenviron 變數所傳回) 將會變更,不過 envp 所指向的區塊將不會變更。 如需有關如何隱藏環境處理的詳細資訊,請參閱自定義 C++ 命令行處理。
envp 引數與 C89 標準相容,但與 C++ 標準不相容。
main 的範例引數
以下範例演示如何使用 argc、argv 和 envp 引數來執行 main:
// argument_definitions.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h>
using namespace std;
int main( int argc, char *argv[], char *envp[] )
{
bool numberLines = false; // Default is no line numbers.
// If /n is passed to the .exe, display numbered listing
// of environment variables.
if ( (argc == 2) && _stricmp( argv[1], "/n" ) == 0 )
numberLines = true;
// Walk through list of strings until a NULL is encountered.
for ( int i = 0; envp[i] != NULL; ++i )
{
if ( numberLines )
cout << i << ": "; // Prefix with numbers if /n specified
cout << envp[i] << "\n";
}
}
剖析 C++ 命令列引數
Microsoft C/C++ 程式碼所使用的命令行剖析規則專屬於 Microsoft。 執行階段啟動程式碼在解譯作業系統命令列所指定的引數時會使用這些規則:
引數會以空白或定位鍵的泛空白字元 (White Space) 進行分隔。
第一個引數 (
argv[0]) 是特別處理。 這代表程式名稱。 因為這必須是有效的路徑名稱,所以允許以雙引號 (") 括住的部分。argv[0]輸出中未包含雙引號標記。 以雙引弧括住的部分可防止將空格或定位字元解譯為引數的結尾。 此清單中的後續規則不適用。用雙引號括住的字串會被解譯成單一引數,其中可能包含空白字元。 有引號的字串可以內嵌到引數中。 插入號 (
^) 不會被辨識為逸出字元或分隔符號。 在引號字串中,一對雙引號會解譯為單一逸出雙引號標記。 如果命令行在找到結尾雙引號之前結束,則到目前為止讀取的所有字元都會輸出為最後一個引數。前面有反斜線 (
\") 的雙引號會解譯為常值雙引號 (")。反斜線會逐字解譯,除非後面緊接著雙引號。
如果雙引號前面有偶數數目的反斜線,則會將每一對反斜線 (
\) 的其中一個反斜線 (argv) 放到\\陣列中,並將雙引號 (") 解譯為字串分隔符號。如果雙引號前面有奇數數目的反斜線,則會將每一對反斜線 (
\) 的的其中一個反斜線 (argv) 放在\\陣列中。 雙引號被其餘反斜線解譯為逸出序列,導致常值雙引號 (") 置於argv中。
命令行引數剖析的範例
下列程式示範如何傳遞命令行引數:
// command_line_arguments.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main( int argc, // Number of strings in array argv
char *argv[], // Array of command-line argument strings
char *envp[] ) // Array of environment variable strings
{
int count;
// Display each command-line argument.
cout << "\nCommand-line arguments:\n";
for( count = 0; count < argc; count++ )
cout << " argv[" << count << "] "
<< argv[count] << "\n";
}
剖析命令行的結果
以下表格顯示範例輸入和預期的輸出,示範上述清單中的規則。
| 命令列輸入 | argv[1] | argv[2] | argv[3] |
|---|---|---|---|
"abc" d e |
abc |
d |
e |
a\\b d"e f"g h |
a\\b |
de fg |
h |
a\\\"b c d |
a\"b |
c |
d |
a\\\\"b c" d e |
a\\b c |
d |
e |
a"b"" c d |
ab" c d |
萬用字元展開
Microsoft 編譯程式選擇性地可讓您使用萬用字元、問號 (?) 和星號 (*) ,在命令行上指定檔名和路徑引數。
命令行引數是由執行階段啟動程式碼中的內部常式所處理,預設不會將萬用字元展開為 argv 字串陣列中的個別字串。 您可以在 setargv.obj 編譯程式選項或 wsetargv.obj 命令列中包含 wmain 檔案 (/link 的 LINK 檔案) 來啟用萬用字元展開。
如需執行階段啟動連結器選項的詳細資訊,請參閱連結選項。
自訂 C++ 命令列處理
如果您的程式不接受命令列引數,您可以隱藏命令列處理常式,藉此稍微節省空間。 若要隱藏其使用,請在 noarg.obj 編譯程式選項或 main 命令行中包含 wmain 檔案 (適用於 /link 和 LINK) 。
同樣地,如果您從未透過 envp 引數存取環境資料表格,則可以隱藏內部環境處理常式。 若要隱藏其使用,請在 noenv.obj 編譯程式選項或 main 命令行中包含 wmain 檔案 (適用於 /link 和 LINK) 。
您的程式可能會呼叫 C 執行階段程式庫中的 spawn 或 exec 常式系列。 如果是這種情況,您就不應該隱藏環境處理常式,因為這個常式會用來將環境從父流程傳遞至子流程。