C++main函数与命令行参数,退出程序
本文翻译自:https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=vs-2019
(除动态链接库dll,静态链接库lib工程外)所有的C++程序都必须有一个main函数。如果你编译一个没有main函数的C++exe工程,编译器会提示错误。main函数是你的代码开始执行的地方,但在main函数调用前,所有的没有被显示初始化的static类成员都被设置为零。在微软C++中,调用main函数前全局静态对象也会被初始化。main函数相对于其他函数而言有以下不同之处:
- 不能被重载
- 不能被声明为inline,内联函数
- 不能被声明为static
- 不能获取它的地址,Cannot have its address taken
- 不能被调用
main函数并没有声明,因为它是语言内置的。如果有的话,其形式如下所示:
int main();
int main(int argc, char *argv[], char *envp[]);
- Microsoft Specific
如果你的代码文件使用的是Unicode wide character,你可以使用wmain,是main函数的款字符版本,其声明如下:
int wmain( );
int wmain(int argc, wchar_t *argv[], wchar_t *envp[]);
你还可以使用_tmain,该函数定义在tchar.h。_tmain被解释为main,除非你定义了_UNICODE(在这种情况下,_tmain被解释为wmain)。
如果main函数的返回值没有指定,编译器会提供一个值为零的返回值。另外,main wmain可以被声明为返回为void(没有返回值)。如果你将main wmain声明为void,name你就不能通过return语句将exit code返回给程序的父进程或系统。在main wmain是void的时候,你需要使用the exit function来返回exit code。
- END Microsoft Specific
Command line arguments
main或wmain的参数可以方便地在命令行中解析参数,并可以选择性地获取环境变量。argc argv的类型由语言进行定义。argc argv envp是典型的变量名称,但是你也可以任意命名:
int main( int argc, char* argv[], char* envp[]);
int wmain( int argc, wchar_t* argv[], wchar_t* envp[]);
这些变量的定义如下:
- argc:用于表明argv变量中参数的个数的一个int值。argc的值总是大于等于1
- argv:一个空终止符的string组成的数组,该参数由用户输入。按照惯例,argv[0]是该程序被调用的命令;argv[1]是第一个命令行参数,之后的是第二三。。。个参数,直到argv[argc],该参数总是NULL。
注意:
- 第一个命令行参数总是argv[1],最后一个总是argv[argc-1]
- By convention,
argv[0]
is the command with which the program is invoked. However, it is possible to spawn a process using CreateProcess and if you use both the first and second arguments (lpApplicationName and lpCommandLine),argv[0]
may not be the executable name; use GetModuleFileName to retrieve the executable name, and its fully-qualified path.
- envp
The envp array, which is a common extension in many UNIX systems, is used in Microsoft C++. It is an array of strings representing the variables set in the user's environment. This array is terminated by a NULL entry. It can be declared as an array of pointers to char (char *envp[]
) or as a pointer to pointers to char (char **envp
). If your program uses wmain
instead of main
, use the wchar_t data type instead of char. The environment block passed to main
and wmain
is a "frozen" copy of the current environment. If you subsequently change the environment via a call to putenv
or _wputenv
, the current environment (as returned by getenv
or _wgetenv
and the _environ
or _wenviron
variable) will change, but the block pointed to by envp will not change. See Customizing Command Line Processing for information on suppressing environment processing. This argument is ANSI compatible in C, but not in C++.
- 例子:
// argument_definitions.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h> using namespace std;
int main( int argc, char *argv[], char *envp[] ) {
int iNumberLines = ; // Default is no line numbers. // If /n is passed to the .exe, display numbered listing
// of environment variables. if ( (argc == ) && _stricmp( argv[], "/n" ) == )
iNumberLines = ; // Walk through list of strings until a NULL is encountered.
for( int i = ; envp[i] != NULL; ++i ) {
if( iNumberLines )
cout << i << ": " << envp[i] << "\n";
}
}
解析C++命令行参数
Microsoft C / C ++启动代码在解释操作系统命令行上给定的参数时使用以下规则:
- 参数由空格(while space)分割,空格可能是space,也可能是tab
- The caret character (^) is not recognized as an escape character or delimiter.字符^并不会被识别为转义字符或分隔符。命令行参数在传递给argv数组前,完全由系统的command-line parser处理。
- 由双引号(“”)包围的字符串不管里面有多少个空格都会被解释为一个参数,带有引号的字符串可以嵌入到一个参数中
- 以反斜杠(\)开头的双引号(即:\")被解释为双引号字符。A double quotation mark preceded by a backslash (\") is interpreted as a literal double quotation mark character (").
- 斜杠(backslash)按照字面意思进行解释,不管它是否在双引号之前
- 如果偶数个斜杠后面跟着一个双引号,则每连续的两个斜杠被解释为一个斜杠到argv中,双引号被解释为字符串定界符,具体看下面的表格
- 如果奇数个斜杠后面跟着一个双引号,则每连续的一对(pair)斜杠被解释为一个斜杠,双引号被解释为''到argv(and the double quotation mark is "escaped" by the remaining backslash, causing a literal double quotation mark (") to be placed in
argv
)
Results of parsing command lines
Command-Line Input | 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 |
例子:
// 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 = ; count < argc; count++ )
cout << " argv[" << count << "] "
<< argv[count] << "\n";
}
通配符扩展Wildcard expansion
你可以使用通配符-问好(?)和星号(*)-用于在命令行上指定文件名和路径变量。
Command-line arguments are handled by a routine called _setargv
(or _wsetargv
in the wide-character environment), which by default does not expand wildcards into separate strings in the argv
string array. For more information on enabling wildcard expansion, refer to Expanding Wildcard Arguments.
Customizing C++ command-line processing
Microsoft Specific
If your program does not take command-line arguments, you can save a small amount of space by suppressing use of the library routine that performs command-line processing. This routine is called _setargv
and is described in Wildcard Expansion. To suppress its use, define a routine that does nothing in the file containing the main
function, and name it _setargv
. The call to _setargv
is then satisfied by your definition of _setargv
, and the library version is not loaded.
Similarly, if you never access the environment table through the envp
argument, you can provide your own empty routine to be used in place of _setenvp
, the environment-processing routine. Just as with the _setargv
function, _setenvp
must be declared as extern "C".
Your program might make calls to the spawn
or exec
family of routines in the C run-time library. If it does, you shouldn't suppress the environment-processing routine, since this routine is used to pass an environment from the parent process to the child process.
END Microsoft Specific
退出程序
在C++中,可以使用如下三种方式退出程序:
- 调用exit函数
- 调用abort函数
- 在main函数中执行return语句
exit函数
exit函数是在头文件<stdlib.h>中声明的,用于结束C++程序。传递给exit函数的值作为程序的return code或exit code被传递给操作系统。通常情况下,返回一个零表示程序成功地结束。你可以使用常量EXIT_FAILURE,EXIT_SUCCESS来表明程序是成功退出,还是失败退出,这两个常量也定义在<stdlib.h>。
在main函数中使用return语句与调用exit函数并将return的值作为其参数是等价的。
abort函数
abort函数也是在<stdlib.h>头文件中声明的。exit与abort函数的不同之处在于exit允许C++运行时终止进程(run-time termination processing)生效(调用全局对象的析构函数),而abort函数是立即终止程序。abort函数绕过(bypass)已初始化的全局静态对象的正常销毁过程,并绕过使用atexit函数指定的任何特殊过程。
atexit函数
使用atexit函数可以指定一些特殊行为在程序结束前执行。在执行退出处理函数前,不会再atexit函数调用前销毁已经初始化的全局静态对象。 No global static objects initialized prior to the call to atexit are destroyed prior to execution of the exit-processing function.
return statement in main
在main函数中使用return语句与调用exit函数是等价的。看下面的例子:
// return_statement.cpp
#include <stdlib.h>
int main()
{
exit( );
return ;
}
上面例子中的exit和return在功能上是等价的。然而,C++要求main函数有返回类型,而不是返回一个void。However, C++ requires that functions that have return types other than void return a value.return语句允许你从main函数中返回一个值。
静态对象的销毁Destruction of static objects
当你调用exit或在main函数中使用return时,静态对象以它们初始化时相反的顺序进行销毁(如果atexit函数存在的话,则这些对象的销毁晚于atexit),下面的例子展示了静态对象的初始化和清除是如何工作的。
在下面的例子中,静态对象sd1 sd2是在进入main函数之前创建及初始化的。在程序通过return结束后,sd2首先被销毁,之后是sd1。ShowData类的析构函数关闭与这些静态对象相关联的文件。
// using_exit_or_return1.cpp
#include <stdio.h>
class ShowData {
public:
// Constructor opens a file.
ShowData( const char *szDev ) {
errno_t err;
err = fopen_s(&OutputDev, szDev, "w" );
} // Destructor closes the file.
~ShowData() { fclose( OutputDev ); } // Disp function shows a string on the output device.
void Disp( char *szData ) {
fputs( szData, OutputDev );
}
private:
FILE *OutputDev;
}; // Define a static object of type ShowData. The output device
// selected is "CON" -- the standard output device.
ShowData sd1 = "CON"; // Define another static object of type ShowData. The output
// is directed to a file called "HELLO.DAT"
ShowData sd2 = "hello.dat"; int main() {
sd1.Disp( "hello to default device\n" );
sd2.Disp( "hello to file hello.dat\n" );
}
上述代码的另一种写法是通过block scope来声明ShowData对象,当离开范围(scope)时销毁这些对象:
int main() {
ShowData sd1, sd2( "hello.dat" ); sd1.Disp( "hello to default device\n" );
sd2.Disp( "hello to file hello.dat\n" );
}
C++main函数与命令行参数,退出程序的更多相关文章
- 解析main函数的命令行参数
原创文章,转载请正确注明本文原始URL及作者. 介绍 写C/C++程序,我们常常需要把main函数的参数作为选项来传递.在linux中,解析选项有专门的函数可以用. int getopt(int ar ...
- Unix系统编程()main函数的命令行参数
命令行参数输入双引号是什么效果? 好像可以去空格化.
- 第33课 main函数与命令行参数
main函数的概念: 测试程序: 以上四种定义main函数的方法都是正确的. main函数的本质: 操作系统是希望main函数的有返回值的,这样可以知道main函数的退出状态. 如果程序时异常退出的, ...
- C++-main函数与命令行参数
1.main函数的概念 C语言中main函数称之为主函数 —个C程序是从main函数开始执行的 下面的main函数定义正确吗? //1 main(){ } //2 void main(){ } //3 ...
- main函数与命令行参数
main函数的概念 C语言中main函数称之为主函数 一个c程序从main函数开始执行的 下面的main函数定义正确吗? main函数的本质 main函数是操作系统调用的函数 操作系统总是将main函 ...
- getopt_long函数解析命令行参数
转载:http://blog.csdn.net/hcx25909/article/details/7388750 每一天你都在使用大量的命令行程序,是不是感觉那些命令行参数用起来比较方便,他们都是使用 ...
- Java的main函数(命令行传参)
javac :编译命令 java :执行命令
- [笔记] 命令行参数 int main(int argc,char *argv[])
int main(int argc,char *argv[]) // argument count 变量个数 argument values 变量值 C程序的main函数有两个形参* argc:整数, ...
- Go 命令行参数,JSON 序列化与反序列化
#### Go 命令行参数,JSON 序列,反序列化这一节来学习一下Go 如果解析命令行参数,以及JSON 的序列化及反序列化; 命令行参数对于熟悉Linux 的同学来说比较清楚,如: ls -a , ...
随机推荐
- 全网最全95道MongoDB面试题1万字详细解析
1.mongodb是什么? MongoDB 是由 C++语言编写的,是一个基于分布式文件存储的开源数据库系统. 在高负载的情况下,添加更多的节点,可以保证服务器性能. MongoDB 旨在给 WEB ...
- nacos部署注意点
官方Naming Configuration Service https://nacos.io/zh-cn/docs/deployment.html 划重点 单机部署 单机部署默认嵌入式存储数据 支持 ...
- 如何在微信小程序中使用阿里字体图标
第一步:下载需要的字体图标 进入阿里图标官网http://iconfont.cn/搜索自己想要的图标. 如这里需要一个购物车的图标,流程为: 搜索“购物车”图标 ---> 点击“添加入库” ...
- Netty 中的内存分配浅析
Netty 出发点作为一款高性能的 RPC 框架必然涉及到频繁的内存分配销毁操作,如果是在堆上分配内存空间将会触发频繁的GC,JDK 在1.4之后提供的 NIO 也已经提供了直接直接分配堆外内存空间的 ...
- firda安装和使用
frida是一个轻量级别的hook框架. frida由两部分组成:一部分是运行在系统上的交互工具frida CLI,另一部分是运行在目标机器上的代码注入工具frida-server. 推荐使用pyth ...
- NativeXml实例训练时注意事项_1
NativeXml实例训练: 1)使用NativeXml操作xml文件时,需要将几个单元文件在Library中引用,配置好这个后面的就可自由训练.或按照自己想要的组合折腾. 2)运行程序调 ...
- jmeter录制app测试脚本
1.jmeter 下载地址 https://jmeter.apache.org 2.选择下载包 3.下载完成后解压即可使用(也可以配置环境变量,但我一般不配置,可以使用) 4.打开jmeter 创建线 ...
- 这一次搞懂SpringMVC原理
@ 目录 前言 正文 请求入口 组件初始化 调用Controller 参数.返回值解析 总结 前言 前面几篇文章,学习了Spring IOC.Bean实例化过程.AOP.事务的源码和设计思想,了解了S ...
- cute-cnblogs 一期样式原文
cute-cnblogs 说明 "我经常有那种感觉,如果这个事情来了,你却没有勇敢地去解决掉,它一定会再来.生活真是这样,它会一次次地让你去做这个功课直到你学会为止." -- &l ...
- 初见NVelocity模板引擎
//using NVelocity.App; //using NVelocity; //using NVelocity.Runtime; VelocityEngine vltEngine = new ...