当你刚开始学习C语言编程的时候,你会在main函数写个printf(“Hello World!");
,以代表你已经进入了这个编程世界,准备开始装X了。
有一天,刚加完班,踩着月色路过咸亨饭馆,想想肚子也饿了,于是进去点了个快餐。拖着疲惫的身躯坐下来,习惯性把手机掏出来看一眼是否有新的消息,抬头一望不远处,孔乙己还在那里喝着酒,啃着茴香豆。他突然走过来,问我:“你是搞IT的吗?”我点了点头,说:“写过几行代码,你也懂这个?”他看着我的回答,越发高兴了,“那我考考你。”他脸上露出沧桑的笑容,发际线快推到了后脑勺了。我心里想,这模样了,也配考我?何况是这么高深的IT知识,你也懂?然而我还是礼貌地说好啊。“你知道main函数怎么写吗?”我吧唧吧唧跟他讲了。他说:“对啊对啊!……main函数有四样写法,你知道么?”我愈不耐烦了,努着嘴走远。孔乙己刚用指甲蘸了酒,想在柜上写字,见我毫不热心,便又叹一口气,显出极惋惜的样子。
好了,我告诉你main函数真的至少有4中写法,我还要告诉你他们有什么区别。(我要开始装X了)
main(){}
void main(void){}
int main(void){return 0;}
int main(int argc, char* argv[]){return 0;}
你将它们参数和返回值再组合一下,可能会得到更多写法。好,现在不聊这个,先了解下它们有什么区别呢?
实践是检验真理的唯一标准。我们可以用以下代码来测试下:
// none_main_none.c
#include <stdio.h>
main()
{
printf("%s\n", __FILE__);
}
// void_main_void.c
#include <stdio.h>
void main(void)
{
printf("%s\n", __FILE__);
}
// int_main_void.c
#include <stdio.h>
int main(void)
{
printf("%s\n", __FILE__);
return 3;
}
// int_main_argc_argv.c
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("%s\n", __FILE__);
printf("%d, %s\n", argc, argv[0]);
return 0;
}
测试完,你应该有答案了。另外,你还会发现,没有返回值类型的main()
实际上编译器会默认给它一个int类型的返回类型。
实际上,这可能是不同C语言标准版本的写法,前面两种有可能你会在嵌入式开发中遇到多点,后面两种是C99的标准。
我们见识下标准原文(ISO/IEC 9899:1999 (E))怎么写的:
5.1.2.2.1 Program startup
The function called at program startup is named main. The implementation declares noprototype for this function. It shall be defined with a return type of int and with noparameters:
int main(void) { /* ... */ }
or with two parameters (referred to here asargc
andargv
, though any names may beused, as they are local to the function in which they are declared):int main(int argc, char *argv[]) { /* ... */ }
or equivalent;9) or in some other implementation-defined manner.If they are declared, the parameters to the main function shall obey the followingconstraints: — The value of
argc
shall be nonnegative. —argv[argc]
shall be a null pointer. — If the value ofargc
is greater than zero, the array membersargv[0]
throughargv[argc-1]
inclusive shall contain pointers to strings, which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment. If the host environment is not capable of supplying strings with letters in both uppercase and lowercase, the implementation shall ensure that the strings are received in lowercase. — If the value ofargc
is greater than zero, the string pointed to byargv[0]
represents the program name;argv[0][0]
shall be the null character if the program name is not available from the host environment. If the value ofargc
is greater than one, the strings pointed to byargv[1]
throughargv[argc-1]
represent the program parameters. — The parametersargc
andargv
and the strings pointed to by theargv
array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.
5.1.2.2.3 Program termination1 If the return type of the main function is a type compatible with int, a return from theinitial call to the main function is equivalent to calling the exit function with the valuereturned by the main function as its argument;10) reaching the } that terminates themain function returns a value of 0. If the return type is not compatible with int, thetermination status returned to the host environment is unspecified.Forward references: definition of terms (7.1.1), the exit function (7.20.4.3).
如果你亲手操作运行测试,并将这段标准内容看一看,你不懂都可以装懂了。
再问一个问题:main
函数的返回值和参数有什么作用?
Talk is cheap, show me the code. ——Linus Torvalds
我们不讲理论,直接上代码:
// plus.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
printf("%s\n", argv[0]);
if(argc == 4)
{
if(argv[2][0] == '+')
{
int sum = atoi(argv[1]) + atoi(argv[3]);
printf("%s %s %s = %d\n", argv[1], argv[2], argv[3], sum);
return 0;
}
else
{
return 2;
}
}
else
{
return 1;
}
}
我们在Linux上用gcc编译并运行来看看 gcc plus.c -o plus
>> ./plus 1 + 1
>> ./plus
>> 1 + 1 = 2
>> echo $?
>> 0
argc
是参数的个数加1,上面例子中./plus 1 + 1
有三个参数(注意以空格隔开各个参数),argc
为4,而argv[0]
是程序名字./plus
。那么echo $?
呢?它是Linux用来查看这个程序的返回值的,即程序运行后的结果, 你可以试试./plus 1 * 1
或者./plus 1 + 1 + 1
会得到不一样的返回值。如果在Windows做测试,你可以用echo %errorlevel%
来查看。
一般情况下,返回值0代表程序运行成功,其他值代表这个各种不同的错误。
到这里,你也许应该明白Linux或者Windows上的各种命令的秘密了吧,例如grep -rn "ABC" ./
,这个grep
就是一个单独的程序做成的命令,而其后面的内容就是各种参数。
我们是不是可以在系统上写几个程序快乐地玩耍了?
等等,骚年,你先别走。老衲再问你两个问题:一个程序真的是从main函数开始的吗?main函数的名字是不是一定要写成main,写成your_main_a行不行?
欲知后事如何,且听下回分解。