关于C语言的voidmain.docx
- 文档编号:17915502
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:78
- 大小:75.63KB
关于C语言的voidmain.docx
《关于C语言的voidmain.docx》由会员分享,可在线阅读,更多相关《关于C语言的voidmain.docx(78页珍藏版)》请在冰点文库上搜索。
关于C语言的voidmain
关于C语言的voidmain()
作者:
admin发布时间:
2012-02-1317:
41来源:
C语言中文网
人围观
分享到:
QQ空间新浪微博人人网腾讯微博豆瓣15
很多人甚至市面上的一些书籍,都使用了voidmain(),其实这是错误的。
C/C++中从来没有定义过voidmain()。
C++之父BjarneStroustrup在他的主页上的FAQ中明确地写着Thedefinitionvoidmain(){/*...*/}isnotandneverhasbeenC++,norhasitevenbeenC.(voidmain()从来就不存在于C++或者C)。
下面我分别说一下C和C++标准中对main函数的定义。
一、C语言中的main()
在C89中,main()是可以接受的。
BrianW.Kernighan和DennisM.Ritchie的经典巨著TheCprogrammingLanguage2e(《C程序设计语言第二版》)用的就是main()。
不过在最新的C99标准中,只有以下两种定义方式是正确的:
intmain(void)
intmain(intargc,char*argv[])
(参考资料:
ISO/IEC9899:
1999(E)Programminglanguages?
C5.1.2.2.1Programstartup)
当然,我们也可以做一点小小的改动。
例如:
char*argv[]可以写成char**argv;argv和argc可以改成别的变量名(如intval和charval),不过一定要符合变量的命名规则。
如果不需要从命令行中获取参数,请用intmain(void);否则请用intmain(intargc,char*argv[])。
main函数的返回值类型必须是int,这样返回值才能传递给程序的调用者(如操作系统)。
如果main函数的最后没有写return语句的话,C99规定编译器要自动在生成的目标文件中(如exe文件)加入return0;,表示程序正常退出。
不过,我还是建议你最好在main函数的最后加上return语句,虽然没有这个必要,但这是一个好的习惯。
注意,vc6不会在目标文件中加入return0;,大概是因为vc6是98年的产品,所以才不支持这个特性。
现在明白我为什么建议你最好加上return语句了吧!
不过,gcc3.2(Linux下的C编译器)会在生成的目标文件中加入return0;。
二、C++中的main()
C++98中定义了如下两种main函数的定义方式:
intmain()
intmain(intargc,char*argv[])
参考资料:
ISO/IEC14882(1998-9-01)Programminglanguages?
C++3.6Startandtermination
intmain()等同于C99中的intmain(void);intmain(intargc,char*argv[])的用法也和C99中定义的一样。
同样,main函数的返回值类型也必须是int。
如果main函数的末尾没写return语句,C++98规定编译器要自动在生成的目标文件中加入return0;。
同样,vc6也不支持这个特性,但是g++3.2(Linux下的C++编译器)支持。
三、关于voidmain()
在C和C++中,不接收任何参数也不返回任何信息的函数原型为“voidfoo(void);”。
可能正是因为这个,所以很多人都误认为如果不需要程序返回值时可以把main函数定义成voidmain(void)。
然而这是错误的!
main函数的返回值应该定义为int类型,C和C++标准中都是这样规定的。
虽然在一些编译器中,voidmain可以通过编译(如vc6),但并非所有编译器都支持voidmain,因为标准中从来没有定义过voidmain。
g++3.2中如果main函数的返回值不是int类型,就根本通不过编译。
而gcc3.2则会发出警告。
所以,如果你想你的程序拥有很好的可移植性,请一定要用intmain。
不要用“我的老师告诉我这么做是对的”之类的话来为自己开脱;老师们总是习惯犯错误(teachershaveabadhabitofbeingwrong)。
写安全的,合乎标准的代码,大家就可以专注于你程序中其它的问题而不是在这种规范方面的东西上浪费时间。
应当指出:
在某些系统中,若程序使用voidmain定义或没有return值,则可能导致堆栈异常从而导致系统故障。
(详见后面英文部分)
四、返回值的作用
main函数的返回值用于说明程序的退出状态。
如果返回0,则代表程序正常退出;返回其它数字的含义则由系统决定。
通常,返回非零代表程序异常退出。
下面我们在winxp环境下做一个小实验。
首先编译下面的程序:
intmain(void)
{
return0;
}
然后打开附件里的“命令提示符”,在命令行里运行刚才编译好的可执行文件,然后输入“echo%ERRORLEVEL%”,回车,就可以看到程序的返回值为0。
假设刚才编译好的文件是a.exe,如果输入“a&&dir”,则会列出当前目录下的文件夹和文件。
但是如果改成“return-1”,或者别的非0值,重新编译后输入“a&&dir”,则dir不会执行。
因为&&的含义是:
如果&&前面的程序正常退出,则继续执行&&后面的程序,否则不执行。
也就是说,利用程序的返回值,我们可以控制要不要执行下一个程序。
这就是intmain的好处。
如果你有兴趣,也可以把main函数的返回值类型改成非int类型(如float),重新编译后执行“a&&dir”,看看会出现什么情况,想想为什么会出现那样的情况。
顺便提一下,如果输入a||dir的话,则表示如果a异常退出,则执行dir。
五、那么intmain(intargc,char*argv[],char*envp[])呢?
这当然也不是标准C/C++里面定义的东西!
char*envp[]是某些编译器提供的扩展功能,用于获取系统的环境变量。
因为不是标准,所以并非所有编译器都支持,故而移植性差,不推荐使用——除非你的程序是专门设计用于工作在特定的环境中而且需要获取系统的环境变量。
在C语言有一定基础之后,怎么样能够更快的成长?
作者:
admin发布时间:
2012-02-1318:
49来源:
C语言中文网
人围观
分享到:
QQ空间新浪微博人人网腾讯微博豆瓣0
这个问题比较常见,通常在程序语言有了一定基础之后,成长最快的方法就是多编程序,没有其他任何捷径,在实践中碰到问题/排查问题,提高程序的实现能力和调试能力,在实践中自然而然将各种知识融会贯通,在实现程序的过程中注意体会每个问题的解决方法以及每个Bug的排除方法,实践能力提高了,程序设计的技巧和能力也就提高了.
祝大家的程序越写越好!
写好C程序的10条秘籍
作者:
admin发布时间:
2012-02-1518:
22来源:
C语言中文网
人围观
分享到:
QQ空间新浪微博人人网腾讯微博豆瓣16
神乎其技,惟C程序,功到自成,十大建议!
1.汝应频繁催动lint工具,据其语法声明修习内力,此事皆因lint之思虑决断实远在君上。
2.不可依随NULL指针,如若不然,混沌痴颠必俟君于彼岸。
3.纵有天赋大智慧,知晓其事无碍,汝亦当尽数强制挪移函数参数为原型所期之数据类型,以免一时疏忽,致使数据类型向汝讨还血债。
4.若头文件未于函数原型之中声明返回值类型,汝当亲为此事,更须谨慎再三,以防不测降临汝身。
5.汝须亲核字符串、数组操作之越界与否。
古之圣人有言:
尝祈门人对答“然也”,不意门人答曰“吾了然于胸无须多虑尽请宽心他日趋庭必当重谢”――所期者短,所获者长,此于数组,实最险要处也。
6.若函数声明内提及,于异常时将返回错误代码云云,汝当谨慎校核该返回值。
或有校核语句使汝之代码增大数倍,令汝之手指因敲键而痛楚莫名之事,汝亦当如此。
不然,汝固以为此异常之事难得一见,上苍亦必借此惩戒汝之傲慢。
7.汝应研习库函数,不当亲笔重写之。
如是,汝之代码必短小易读,汝之心境必清爽恬淡。
8.纵汝不愿,汝亦应借括号、缩进之属,使汝之代码间架清晰,可为后者借鉴。
汝之大智慧施于决疑解难则可,施于敷设谜团、淆乱文体则万万不可。
9.外部标识符之前六字符当与众不同。
此律法看似粗陋,和者寥寥,然其效用自能延续永远。
汝若不从此言,他日,汝欲连接程序于旧作之上时,必抓耳挠腮、蓬头垢面,狼狈之相尽现矣。
10.或有族类,大言炎炎,云“普天之下,莫非VAX”。
于此等异端,汝当摒弃之、断绝之、远避之。
更有异人,笃信魔道,以为纵汝所用电脑频繁换代,汝之程序亦能长久适用。
汝亦不可与此类恶人来往,谨记谨记
C语言中史上最愚蠢的Bug
作者:
admin发布时间:
2012-02-1518:
59来源:
C语言中文网
人围观
分享到:
QQ空间新浪微博人人网腾讯微博豆瓣8
本文来自“ThemoststupidCbugever”,很有意思,分享给大家。
我相信这样的bug,就算你是高手你也会犯的。
你来看看作者犯的这个Bug吧。
。
首先,作者想用一段程序来创建一个文件,如果有文件名的话,就创建真正的文件,如果没有的话,就调用?
tmpfile()?
创建临时文件。
他这段程序就是HTTP下载的C程序。
code==200就是HTTP的返回码。
elseif(code==200){//Downloadingwholefile
/*Writenewfile(plusallowreadingoncewefinish)*/
g=fname?
fopen(fname,"w+"):
tmpfile();}
但是这个程序,只能在Unix/Linux下工作,因为Microsoft的?
tmpfile()的实现?
居然选择了C:
作为临时文件的存放目录,这对于那些没有管理员权限的人来说就出大问题了,在Windows7下,就算你有管理员权限也会有问题。
所以,上面的程序在Windows平台下需要用不同的方式来处理,不能直接使用Windows的tmpfile()函数。
于是作者就先把这个问题记下来,在注释中写下了FIXME:
elseif(code==200){//Downloadingwholefile
/*Writenewfile(plusallowreadingoncewefinish)*/
//FIXMEWin32nativeversionfailsherebecause
//Microsoft’sversionoftmpfile()createsthefileinC:
g=fname?
fopen(fname,"w+"):
tmpfile();}
然后,作者觉得需要写一个跨平台的编译:
FILE*tmpfile(void){
#ifndef_WIN32
returntmpfile();
#else
//codeforWindows;
#endif
}
然后,作者觉得这样实现很不好,会发现名字冲突,因为这样一来这个函数太难看了。
于是他重构了一下他的代码——写一个自己实现的tmpfile()–w32_tmpfile,然后,在Windows下用宏定义来重命名这个函数为tmpfile()。
(注:
这种用法是比较标准的跨平台代码的写法)
#ifdef_WIN32
#definetmpfilew32_tmpfile
#endif
FILE*w32_tmpfile(void){
//codeforWindows;
}
搞定!
编译程序,运行。
靠!
居然没有调用到我的w32_tmpfile(),什么问题?
调试,单步跟踪,果然没有调用到!
难道是问号表达式有问题?
改成if–else语句,好了!
if(NULL!
=fname){
g=fopen(fname,"w+");
}else{
g=tmpfile();
}
问号表达式不应该有问题吧,难道我们的宏对问号表达式不起作用,这难道是编译器的预编译的一个bug?
作者怀疑到。
现在我们把所有的代码连在一起看,并比较一下:
能工作的C语言代码
#ifdef_WIN32
#definetmpfilew32_tmpfile
#endif
FILE*w32_tmpfile(void){
codeforWindows;
}elseif(code==200){
//Downloadingwholefile
/*Writenewfile(plusallowreadingoncewefinish)*/
//FIXMEWin32nativeversionfailsherebecause
//Microsoft’sversionoftmpfile()createsthefileinC:
//g=fname?
fopen(fname,"w+"):
tmpfile();
if(NULL!
=fname){
g=fopen(fname,"w+");
}else{
g=tmpfile();
}
}
不能工作的C语言代码
#ifdef_WIN32
#definetmpfilew32_tmpfile
#endif
FILE*w32_tmpfile(void){
codeforWindows;
}elseif(code==200){
//Downloadingwholefile
/*Writenewfile(plusallowreadingoncewefinish)*/
//FIXMEWin32nativeversionfailsherebecause
//Microsoft’sversionoftmpfile()createsthefileinC:
g=fname?
fopen(fname,"w+"):
tmpfile();
}
也许你在一开始就看到了这个bug,但是作者没有。
所有的问题都出在注释上:
/*Writenewfile(plusallowreadingoncewefinish)*/
//FIXMEWin32nativeversionfailsherebecause
//Microsoft’sversionoftmpfile()createsthefileinC:
你看到了最后那个C:
吗?
在C中,“”代表此行没有结束,于是,后面的代码也成了注释。
这就是这个bug的真正原因!
而之所以改成if-else能工作的原因是因为作者注释了老的问号表达式的代码,所以,那段能工作的代码成了:
/*Writenewfile(plusallowreadingoncewefinish)*/
//FIXMEWin32nativeversionfailsherebecauseMicrosoft’sversionoftmpfile()createsthefileinC:
//g=fname?
fopen(fname,"w+"):
tmpfile();
if(NULL!
=fname){
g=fopen(fname,"w+");
}else{
g=tmpfile();
}
我相信,当作者找到这个问题的原因后,一定会骂一句“妈的”!
我也相信,这个bug花费了作者很多时间!
最后,我也share一个我以前犯的一个错。
我有一个小函数,需要传入一个int*pInt的类型,然后我需要在我的代码里把这个int*pInt作除数。
于是我的代码成了下面的这个样子:
floatresult=num/*pInt;
….
/*somecomments*/
-x<10?
f(result):
f(-result);
因为我在我当时用vi编写代码,所以没有语法高亮,而我的程序都编译通过了,但是却出现了很奇怪的事。
我也不知道,用gdb调式的时候,发现有些语句直接就过了。
这个问题让我花了很多时间,最后发现问题原来是没有空格导致的,TNND,下面我用代码高亮的插件来显示上面的代码,
floatresult=num/*pInt;....
/*somecomments*/
-x<10?
f(result):
f(-result);
HollyShit!
我的代码成了:
floatresult=num-x<10?
f(result):
f(-result);
妈的!
我的这个错误在愚蠢程度上和上面那个作者出的错误有一拼
对于C语言,该如何选择进程与线程
作者:
admin发布时间:
2012-02-1721:
33来源:
C语言中文网
人围观
分享到:
QQ空间新浪微博人人网腾讯微博豆瓣1
进程vs线程,如何选择?
我们编写程序,到底是采用多线程还是多进程?
这里是有区别的,采用不同的机制能够获得的效率也不一样。
如何选择适合我们自己的程序的机制呢?
下面是一些常见的选择的看法,不过也只是提供给大家参考参考,具体设计的时候还是要自己处理。
一个程序里面的所有的线程都在同一个运行空间中执行。
而一个程序的子进程则是运行在另外的执行空间中的,这里是通过调用了exec函数来实现的。
同一个进程中的某个线程的故障可以影响其它的线程,因为所有的线程共享同一个虚拟内存空间以及其他资源。
例如,某个线程对没有初始化的指针进行写操作,就可能影响其它的线程。
而一个出了问题的进程是不会影响其它的进程的,因为它们分别在不同的进程空间进行自己的操作。
创建新的进程需要进行内存的拷贝操作,这就额外的增加了系统负担,而线程则不需要这个拷贝过程。
不过由于现在的操作系统的实现是仅仅当内存需要改变的时候才拷贝改动的部分,所以这里的影响相对还是比较小的。
线程通常用在某些需要比较好的同步操作的场合。
例如,某个问题可以分解为多个几乎对等同步处理的任务的话,则是用线程是很好的选择。
进程则适合应用在不需要严格的同步的场合。
线程之间共享数据是很方便的,因为不同的线程本来就是共享同样的存储空间。
(然而这里就要非常仔细的处理竞争的情况。
)而不同进程之间共享数据则需要使用一些ipc机制,例如管道、共享内存、套接字等等
三款C语言编程软件对比【优缺点】
作者:
admin发布时间:
2012-02-1922:
20来源:
C语言中文网
人围观
分享到:
QQ空间新浪微博人人网腾讯微博豆瓣0
常用的C语言编程软件有VisualStdio6.0、TuborC和Win-TC等等,笔者下面就三款软件的优点和缺点做一下简单地对比。
1.VisualStdio6.0:
一般简称VC(版本是6.0),这款软件是使用最多的一款C语言编程软件,有简装版、绿色版、企业版等各个不同的版本,可以满足不同人的需求。
注:
企业版的安装有点困难。
2.TuborC:
小巧快速,但是界面是DOS风格的,不好看,并且不习惯!
3.Win-TC:
体积比较小,界面也漂亮,但是有一些用户反应再编程的过程中无法输入汉字。
C语言的应用范围和发展前途简介
作者:
admin发布时间:
2012-02-1922:
38来源:
C语言中文网
人围观
分享到:
QQ空间新浪微博人人网腾讯微博豆瓣6
C一般用来底层开发,如操作系统,嵌入式开发,或者要求效率,高可移植性的地方。
C对人要求很高,程序员要考虑的地方太多。
他的特点就是每一个字节都可以精确控制,不象C++,编译器为你自动加的东西太多,效率也就低了。
windows就是用它来开发的,linux很多程序也用它来写。
例如:
用C语言编写简单的接口程序.在当今,流行的编程软件种类繁多,它们编程方便、易于维护,但是在与硬件直接打交道和编制系统软件时却束手无策,于是C语言就有了用武之地。
C语言作为汇编语言与高级语言之间的一种过渡语言,兼有汇编语言的高效和高级语言的方便。
在通讯中,为了保证行运安全可靠,标准的串行口必须具有许多握手信号和状态信息。
这是因为通讯的各个计算机CPU速度不一样(这会导致“错帧”)以及发送机发送数据速度比接收机接收速度快(这会导致“过冲”)。
为解决这个问题,我们采用一个简单的握手信号,即发送机每次仅发送半个字节(低4位)的数据,而另外半个字节(高4位)则用来传送信息。
我们可以对信息位(高4位)进行如下简单的编码:
0H:
发送的是新的半个字节数据
1H:
重新发送上次传送错误的数据
2H:
文件名结束
3H:
文件结束
这样,每当发送机发送一个字节以后,就等待接受机发回送信号,这回送信号就是发送机发送过来的那个字节。
发送机接收到回送信号后,把它与刚发送的字节相比较,如果相同,就发送新的半个字节,否则就重新发送。
新数据与旧数据通过信息位来区分。
下面就是我用C语言编写控制串行口的程序。
我们以一个发送文件的程序为例,介绍一下用C语言实现对接口的控制。
用C语言编写简单的接口程序源代码:
#include"dos.h"/*c的特点在于只要有头文件,就能和任意文件接上*/
#include"stdlib.h"
#include"stdio.h"
#definePORT0
voidSendFile(charfname);/*发送文件*/
voidSend(ints);/*发送一个字节*/
voidSendFileName(charfname);/*发送文件名*/
voidReceiveFile();/*接收文件*/
voidGetFileName(charf);/*接收文件名*/
voidInitPort(intport,unsignedcharpara);/*初始化端口*/
voidSendPort(intport,charc);/*端口发送*/
intReadPort(intport);/*读端口字节*/
intCheckState(intport);/*检查端口状态*/
intReceive(intport,intG);/*接收一个字节*/
main(argc,argv)
intargc;
char*argv[];
{
if(argc<2){
printf("PleaseinputR(receive)orS(sent)parametr
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 关于 语言 voidmain