main
函数和命令行参数
所有 C++ 程序都必须具有 main
函数。 如果尝试在没有 main
函数的情况下编译 C++ 程序,编译器将引发错误。 (动态链接库和 static 库没有 main
函数。)main
函数是源代码开始执行的位置,但在程序进入 main
函数之前,没有显式初始值设定项的所有 static 类成员都设为零。 在 Microsoft C++ 中,全局 static 对象在进入 main
前也进行初始化。 一些限制适用于 main
函数,而不适用于任何其他 C++ 函数。 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 宽 character,则可以使用特定于 Microsoft 的 wmain
入口点,即宽 character 版的 main
。 下面是 wmain
的有效声明语法:
int wmain();
int wmain(int argc, wchar_t *argv[]);
还可以使用特定于 Microsoft 的 _tmain
,它是 tchar.h
中定义的预处理器宏。 除非定义了 _UNICODE
,否则 _tmain
解析为 main
。 在该示例中,_tmain
将解析为 wmain
。 对于需要分别生成窄版和宽版 character 集的代码来说,_tmain
宏和以 _t
开头的其他宏非常有用。 有关详细信息,请参阅使用一般文本映射。
从 main 返回 void
main
和 wmain
函数作为 Microsoft 扩展,可以声明为返回 void
(没有返回值)。 此扩展在其他一些编译器中也可用,但不建议使用它。 当 main
不返回值时,它可用于保持对称。
如果将 main
或 wmain
声明为返回 void
,则无法使用 return
语句将 exit 代码返回到父进程或操作系统中。 若要在将 main
或 wmain
声明为 void
时返回 exit 代码,则必须使用 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
的示例参数
下面的示例演示如何使用 main
的 argc
、argv
和 envp
变量:
// 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。 在解释操作系统命令行上给出的参数时,运行时启动代码使用这些规则:
参数用空白分隔,空白可以是一个空格或制表符。
第一个参数 (
argv[0]
) 是经过专门处理的。 它表示程序名称。 因为它必须是有效的路径名,因此允许用双引号 ("
) 括起来一些部分。 双引号不包含在argv[0]
输出中。 用双引号括起来的部分可以防止将空格或 tab character 解释为参数的末尾。 此列表中的后续规则不适用。将双引号括起来的字符串解释为单个参数,哪怕其中可能包含空格 character。 带引号的字符串可以嵌入在自变量内。 未将插入点 (
^
) 识别为转义 character 或者分隔符。 在带引号的字符串中,一对双引号被解释为单个转义的双引号。 如果命令行结束时未发现后双引号,则到目前为止读取的所有 character 将输出为最后一个参数。前面有反斜杠的双引号 (
\"
) 被解释为原义双引号 ("
)。反斜杠按其原义解释,除非它们紧位于双引号之前。
如果偶数个反斜杠后跟双引号,则每对反斜杠 (
\\
) 中有一个反斜杠 (\
) 被置于argv
数组中,而双引号 ("
) 被解释为字符串分隔符。如果奇数个反斜杠后跟双引号,则每对反斜杠 (
\\
) 中有一个反斜杠 (\
) 被置于argv
数组中。 将双引号解释为包含 remaining 反斜杠的转义序列,导致将原义双引号 ("
) 置于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 编译器根据需要允许你使用通配符 character、问号 (?
) 和星号 (*
),以在命令行上指定文件名和路径参数。
命令行参数由运行时启动代码中的内部历程处理,默认情况下,该例程不会将通配符扩展到 argv
字符串数组的单独字符串中。 通过将 setargv.obj
文件(对 wmain
来说为 wsetargv.obj
文件)包括在 /link
编译器选项或 LINK
命令行中,可以启用通配符扩展。
有关运行时启动链接器选项的详细信息,请参阅链接选项。
自定义 C++ 命令行处理
如果程序不采用命令行参数,则可以取消命令行处理例程来节省少量空间。 若要禁止使用该方法,请在 /link
编译器选项或 LINK
命令行中包含 noarg.obj
文件(用于 main
和 wmain
)。
同样,如果从不通过 envp
参数访问环境表,则可以取消内部环境处理例程。 若要禁止使用该方法,请在 /link
编译器选项或 LINK
命令行中包含 noenv.obj
文件(用于 main
和 wmain
)。
程序可以调用 C 运行时库中的 spawn
或 exec
系列例程。 如果是这样,则不应取消环境处理例程,因为可使用它将环境从父进程传递到子进程中。
另请参阅
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈