C语言知识汇总.docx
《C语言知识汇总.docx》由会员分享,可在线阅读,更多相关《C语言知识汇总.docx(20页珍藏版)》请在冰豆网上搜索。
C语言知识汇总
C语言知识汇总
1.用C语言技术进行CGI程序设计
一、CGI概述
CGI(公用网关接口)规定了Web服务器调用其他可执行程序(CGI程序)的接口协议标准。
Web服务器通过调用CGI程序实现和Web浏览器的交互
也就是CGI程序接受Web浏览器发送给Web服务器的信息,进行处理,将响应结果再回送给Web服务器及Web浏览器。
CGI程序一般完成Web网页中表单(Form)数据的处理、数据库查询和实现与传统应用系统的集成等工作。
CGI程序可以用任何程序设计语言编写,如Shell脚本语言、Perl、Fortran、Pascal、C语言等。
但是用C语言编写的CGI程序具有执行速度快、安全性高(因为C语言程序是编译执行且不可被修改)等特点。
CGI接口标准包括标准输入、环境变量、标准输出三部分。
1.标准输入
CGI程序像其他可执行程序一样,可通过标准输入(stdin)从Web服务器得到输入信息,如Form中的数据,这就是所谓的向CGI程序传递数据的POST方法。
这意味着在操作系统命令行状态可执行CGI程序,对CGI程序进行调试。
POST方法是常用的方法,本文将以此方法为例,分析CGI程序设计的方法、过程和技巧。
2.环境变量
操作系统提供了许多环境变量,它们定义了程序的执行环境,应用程序可以存取它们。
Web服务器和CGI接口又另外设置了自己的一些环境变量,用来向CGI程序传递一些重要的参数。
CGI的GET方法还通过环境变量QUERY-STRING向CGI程序传递Form中的数据。
3.标准输出
CGI程序通过标准输出(stdout)将输出信息传送给Web服务器。
传送给Web服务器的信息可以用各种格式,通常是以纯文本或者HTML文本的形式,这样我们就可以在命令行状态调试CGI程序,并且得到它们的输出。
下面是一个简单的CGI程序,它将HTML中Form的信息直接输出到Web浏览器。
#include
#include
main()
{
int,i,n;
printf(″Contenttype:
text/plain\n\n″);
n=0;
if(getenv(″CONTENT-LENGTH″))
n=atoi(getenv(CONTENT-LENGTH″));
for(i=0;i
putchar(getchar());
putchar(′\n′);
fflush(stdout);
}
下面对此程序作一下简要的分析。
:
prinft(″Contenttype:
text/plain\n\n″);
此行通过标准输出将字符串″Contenttype:
text/plain\n\n″传送给Web服务器。
它是一个MIME头信息,它告诉Web服务器随后的输出是以纯ASCII文本的形式。
请注意在这个头信息中有两个新行符,这是因为Web服务器需要在实际的文本信息开始之前先看见一个空行。
if(getenv(″CONTENT-LENGTH″))
n=atoi(getenv(″CONTENT-LENGTH″));
此行首先检查环境变量CONTENT-LENGTH是否存在。
Web服务器在调用使用POST方法的CGI程序时设置此环境变量,它的文本值表示Web服务器传送给CGI程序的输入中的字符数目,因此我们使用函数atoi()将此环境变量的值转换成整数,并赋给变量n。
请注意Web服务器并不以文件结束符来终止它的输出,所以如果不检查环境变量CONTENT-LENGTH,CGI程序就无法知道什么时候输入结束了
for(i=0;iputchar(getchar());
此行从0循环到(CONTENT-LENGTH-1)次将标准输入中读到的每一个字符直接拷贝到标准输出,也就是将所有的输入以ASCII的形式回送给Web服务器。
通过此例,我们可将CGI程序的一般工作过程总结为如下几点。
1.通过检查环境变量CONTENT-LENGTH,确定有多少输入;
2.循环使用getchar()或者其他文件读函数得到所有的输入;
3.以相应的方法处理输入;
4.通过″Contenttype:
″头信息,将输出信息的格式告诉Web服务器;
5.通过使用printf()或者putchar()或者其他的文件写函数,将输出传送给Web服务器。
总之,CGI程序的主要任务就是从Web服务器得到输入信息,进行处理,然后将输出结果再送回给Web服务器。
二、环境变量
环境变量是文本串(名字/值对),可以被OSShell或其他程序设置,也可以被其他程序访问。
它们是Web服务器传递数据给CGI程序的简单手段,之所以称为环境变量是因为它们是全局变量,任何程序都可以存取它们。
下面是CGI程序设计中常常要用到的一些环境变量。
HTTP-REFERER:
调用该CGI程序的网页的URL。
REMOTE-HOST:
调用该CGI程序的Web浏览器的机器名和域名。
REQUEST-METHOD:
指的是当Web服务器传递数据给CGI程序时所采用的方法,分为GET和POST两种方法。
GET方法仅通过环境变量(如QUERY-STRING)传递数据给CGI程序,而POST方法通过环境变量和标准输入传递数据给CGI程序,因此POST方法可较方便地传递较多的数据给CGI程序。
SCRIPT-NAME:
该CGI程序的名称。
QUERY-STRING:
当使用POST方法时,Form中的数据最后放在QUERY-STRING中,传递给CGI程序。
CONTENT-TYPE:
传递给CGI程序数据的MIME类型,通常为″application/x-www-form-urlencodede″,它是从HTMLForm中以POST方法传递数据给CGI程序的数据编码类型,称为URL编码类型。
CONTENT-LENGTH:
传递给CGI程序的数据字符数(字节数)。
在C语言程序中,要访向环境变量,可使用getenv()库函数。
例如:
if(getenv(″CONTENT-LENGTH″))
n=atoi(getenv(″CONTENT-LENGTH″));
请注意程序中最好调用两次getenv():
第一次检查是否存在该环境变量,第二次再使用该环境变量。
这是因为函数getenv()在给定的环境变量名不存在时,返回一个NULL(空)指针,如果你不首先检查而直接引用它,当该环境变量不存在时会引起CGI程序崩溃。
三、From输入的分析和解码
1.分析名字/值对
当用户提交一个HTMLForm时,Web浏览器首先对Form中的数据以名字/值对的形式进行编码,并发送给Web服务器,然后由Web服务器传递给CGI程序。
其格式如下:
name1=value1&name2=value2&name3=value3&name4=value4&...
其中名字是Form中定义的INPUT、SELECT或TEXTAREA等标置(Tag)名字,值是用户输入或选择的标置值。
这种格式即为URL编码,程序中需要对其进行分析和解码。
要分析这种数据流,CGI程序必须首先将数据流分解成一组组的名字/值对。
这可以通过在输入流中查找下面的两个字符来完成。
每当找到字符=,标志着一个Form变量名字的结束;每当找到字符&,标志着一个Form变量值的结束。
请注意输入数据的最后一个变量的值不以&结束。
一旦名字/值对分解后,还必须将输入中的一些特殊字符转换成相应的ASCII字符。
这些特殊字符是:
+:
将+转换成空格符;
%xx:
用其十六进制ASCII码值表示的特殊字符。
根据值xx将其转换成相应的ASCII字符。
对Form变量名和变量值都要进行这种转换。
下面是一个对Form数据进行分析并将结果回送给Web服务器的CGI程序。
#include
#include
#include
inthtoi(char*);
main()
{
inti,n;
charc;
printf(″Contenttype:
text/plain\n\n″);
n=0;
if(getenv(″CONTENT-LENGTH″))
n=atoi(getenv(″CONTENT-LENGTH″));
for(i=0;i
intis-eq=0;
c=getchar();
switch(c){
case′&′:
c=′\n′;
break;
case′+′:
c=′ ′;
break;
case′%′:
{
chars[3];
s[0]=getchar();
s[1]=getchar();
s[2]=0;
c=htoi(s);
i+=2;
}
break;
case′=′:
c=′:
′;
is-eq=1;
break;
};
putchar(c);
if(is-eq)putchar(′ ′);
}
putchar(′\n′);
fflush(stdout);
}
/*converthexstringtoint*/
inthtoi(char*s)
{
char*digits=″0123456789ABCDEF″;
if(islower(s[0]))s[0]=toupper(s[0]);
if(islower(s[1]))s[1]=toupper(s[1]);
return16*(strchr(digits,s[0])-strchr(digits,′0′)
)
+(strchr(digits,s[1])-strchr(digits,′0′));
}
上面的程序首先输出一个MIME头信息给Web服务器,检查输入中的字符数,并循环检查每一个字符。
当发现字符为&时,意味着一个名字/值对的结束,程序输出一个空行;当发现字符为+时,将它转换成空格;当发现字符为%时,意味着一个两字符的十六进制值的开始,调用htoi()函数将随后的两个字符转换为相应的ASCII字符;当发现字符为=时,意味着一个名字/值对的名字部分的结束,并将它转换成字符:
。
最后将转换后的字符输出给Web服务器。
四、产生HTML输出
CGI程序产生的输出由两部分组成:
MIME头信息和实际的信息。
两部分之间以一个空行分开。
我们已经看到怎样使用MIME头信息″Contenttype:
text/plain\n\n″和printf()、putchar()等函数调用来输出纯ASCII文本给Web服务器。
实际上,我们也可以使用MIME头信息″Contenttype:
text/html\n\n″来输出HTML源代码给Web服务器。
请注意任何MIME头信息后必须有一个空行。
一旦发送这个MIME头信息给Web服务器后,Web浏览器将认为随后的文本输出为HTML源代码,在HTML源代码中可以使用任何HTML结构,如超链、图像、Form,及对其他CGI程序的调用。
也就是说,我们可以在CGI程序中动态产生HTML源代码输出,下面是一个简单的例子。
#include
#include
main()
{
printf(″Contenttype:
text/html\n\n″);
printf(″\n″);
printf(″
AnHTMLPageFromaCGI\n″);
printf(″
\n″);
printf(″
ThisisanHTMLpagegeneratedfromwithinaCGIprogram...
\n″);
printf(″
\n″);
printf(″Gobacktooutput.htmlpage<
/b>\n″);
printf(″\n″);
printf(″\n″);
fflush(stdout);
}
上面的CGI程序简单地用printf()函数来产生HTML源代码。
请注意在输出的字符串中如果有双引号,在其前面必须有一个后斜字符\,这是因为整个HTML代码串已经在双引号内,所以HTML代码串中的双引号符必须用一个后斜字符\来转义。
2.WM_CLOSE的运用
1.边框窗口对WM_CLOSE的处理
MFC提供了函数CFrameWnd:
:
OnClose来处理各类边框窗口的关闭:
不仅包括SDI的边框窗口(从CFrameWnd派生),而且包括MDI的主边框窗口(从CMDIFrameWnd派生)或者文档边框窗口(从CMDIChildWnd派生)的关闭。
该函数的原型如下,流程如图6-1所示:
voidCFrameWnd:
:
OnClose()
从图6-1中可以看出,它首先判断是否可以关闭窗口(m_lpfnCloseProc是函数指针类型的成员变量,用于打印预览等情况下),然后,根据具体情况进行处理:
∙如果是主窗口被关闭,则关闭程序的所有文档,销毁所有窗口,退出程序;
∙如果不是主窗口被关闭,则是文档边框窗口被关闭,又分两种情况:
若该窗口所显示的文档被且仅被该窗口显示,则关闭文档和文档窗口并销毁窗口;若该窗口显示的文档还被其他文档边框窗口所显示,则仅仅关闭和销毁文档窗口。
下面是处理WM_CLOSE消息中涉及的一些函数。
∙
BOOLCDocument:
:
SaveModified()
该虚拟函数的缺省实现:
首先调用IsModifed判断文档是否被修改,没有修改就返回,否则继续。
当询问用户是否保存被修改的文档时,若用户表示“cancel”,返回FALSE;若用户表示“no”,则返回TRUE;若用户表示“yes”,则存盘失败返回FALSE,存盘成功返回TRUE。
存盘处理首先要得到被保存文件的名称,然后调用虚拟函数OnSaveDocument完成存盘工作,并使用SetModifidFlag(FALSE)设置文档为没有修改。
∙BOOLCDocument:
:
OnSaveDocument(LPCTSTRlpszPathName)
该函数是虚拟函数,用来保存文件。
其实现的功能和OpOpenDocument相反,但处理流程类似,描述如下:
根据lpszPathName打开文件pFile;
使用pFile构造一个用于写入数据的CArchive对象,此对象用来保存数据到文件;
设置鼠标为时间瓶形状;
使用Serialize函数完成序列化写;
完毕,恢复鼠标的形状。
∙CWinApp:
:
SaveAllModified()
CWinApp:
:
CloseAllDocuments(BOOLbEndSession)
这两个函数都遍历模板管理器列表,并分别对列表中的模板管理器对象逐个调用CDocManager的同名成员函数:
CDocManager:
:
SaveAllModified()
CDocManager:
:
CloseAllDocuments(BOOLbEndSession)
这两个函数都遍历其文档模板列表,并分别对列表中的模板对象逐个调用CDocTemplate的同名成员函数:
CDocTemplate:
:
SaveAllModified()
CDocTemplate:
:
CloseAllDocuments(BOOLbEndSession)
这两个函数都遍历其文档列表,并分别对列表中的文档对象逐个调用CDocuemnt的成员函数:
CDocument:
:
SaveModified()
CDocument:
:
OnCloseDocument()
∙CDocument:
:
SaveModified()
CDocument:
:
OnCloseDocument()
CDocument:
:
SaveModified前面已作了解释。
OnCloseDocument是一个虚拟函数,其流程如图6-2所示。
通过文档对象所对应的视,得到所有显示该文档的边框窗口的指针:
在SDI程序关闭窗口时,获取的是主边框窗口;在MDI程序关闭窗口时,获取的是MDI子窗口。
然后,关闭并销毁对应的边框窗口。
如果文档对象的m_bAutoDelete为真,则销毁文档对象自身。
1.窗口的销毁过程
1.DestroyWindow
从图6-1、图6-2可以看出,销毁窗口是通过调用DestroyWindow来完成的。
DestroyWindow是CWnd类的一个虚拟函数。
CWnd实现了该函数,而CMDIChildWnd覆盖了该函数。
(1)CWnd:
:
DestroyWindow()
主要就是调用:
:
DestroyWindow销毁m_hWnd(必须非空),同时销毁其菜单、定时器,以及完成其他清理工作。
:
:
DestroyWindow使将被销毁的窗口失去激活、失去输入焦点,并发送WM_DESTROY、WM_NCDESTROY消息到该窗口及其各级子窗口。
如果被销毁的窗口是子窗口且没有设置WM_NOPARENTNOTFIY风格,则给其父窗口发送WM_PARENTNOFITY消息。
(2)CMDIChildWnd:
:
DestroyWindow()
因为MDI子窗口不能使用:
:
DestroyWindows来销毁,所以CMdiChildWnd覆盖了该函数,CMDIChildWnd主要是调用成员函数MDIDestroy给客户窗口(父窗口)发送消息WM_MDIDESTROY,让客户窗口来销毁自己。
2.处理WM_DESTROY消息
消息处理函数OnDestroy处理WM_DESTROY消息,CFrameWnd、CMDIChildWnd、CWnd、CView及其派生类(如CEditView等等)、CControlBar等都提供了对该消息的处理函数。
这里,主要解释边框、文档边框、视类的消息处理函数OnDestroy。
1.CWnd:
:
OnDestroy()
调用缺省处理函数Default()。
2.CFrameWnd:
:
OnDestroy()
首先,销毁工具栏的窗口;然后,设置菜单为缺省菜单;接着,如果要销毁的是主边框窗口,则通知HELP程序本应用程序将退出,没有其他程序使用WINHELP则关闭WINHELP;最后调用CWnd:
:
OnDestroy。
3.CMDIFrameWnd:
:
OnDestroy()
首先,调整客户窗口的边界类型;然后,调用基类CframeWnd的OnDestroy。
这时,MDI子窗口的工具栏窗口列表为空,故没有工具栏窗口可以销毁。
4.CView:
:
OnDestroy()
首先,判断自身是否是边框窗口的活动视,如果是则调用边框窗口的SetActivateView使自己失去激活;然后,调用基类CWnd的OnDestroy。
3.处理WM_NCDESTROY消息
窗口的非客户区被销毁时,窗口接收WM_NCDESTROY消息,由OnNcDestroy处理WM_NCDESTROY消息。
在MFC中,OnNcDestroy是Windows窗口被销毁时调用的最后一个成员函数。
CWnd、CView的某些派生类提供了对该消息的处理函数,这里只讨论CWnd的实现。
1.CWnd:
:
OnNcDestroy()
首先判断当前线程的主窗口是否是该窗口,如果是且模块非DLL,则发送WM_QUIT消息,使得程序结束;
然后,判断当前线程的活动窗口是否是该窗口,如果是则设置活动窗口为NULL;
接着,清理Tooltip窗口,调用Default由Windows缺省处理WM_NCDESTROY消息,UNSUBCLASS,把窗口句柄和MFC窗口对象分离(Detach);
最后,调用虚拟函数PostNcDestoy。
2.PostNcDestoy
CWnd、CFrameWnd、CView、CControlBar等都覆盖了该函数。
文档边框窗口和边框窗口都使用CFrameWnd:
:
PostNcDestroy。
∙CWnd:
:
PostNcDestroy()
MFC缺省实现空
∙voidCFrameWnd:
:
PostNcDestroy()
调用deletethis销毁自身这个MFC对象。
∙voidCView:
:
PostNcDestroy()
调用deletethis销毁自身这个MFC对象。
1.析构函数
deletethis导致析构函数的调用。
需要提到的是CFrameWnd和CView的析构函数。
∙CFrameWnd:
:
~CFrameWnd()
边框窗口在创建时,把自身加入到模块-线程状态的边框窗口列表m_frameList中。
现在,从列表中移走该窗口对象。
必要的话,删除m_phWndDisable数组。
∙CView:
:
~CView()
在视创建时,把自身加入到文档对象的视列表中。
现在,从列表中移走该视对象。
应用程序调用CloseAllDocument关闭文档时。
参数为FALSE,它实际上并没有把视从列表中清除,而最后的清除是由析构函数来完成的。
至此,边框窗口关闭的过程讨论完毕。
下面,结合具体情况──SDI窗口的关闭、MDI主窗口的关闭、MDI子窗口的关闭──描述对WM_CLOSE消息的处理。
4.SDI窗口、MDI主、子窗口的关闭
参考图6-1分析SDI窗口、MDI主、子窗口的关闭流程。
1.SDI窗口的关闭
在这种情况下,主窗口将被关闭。
首先,关闭应用程序的文档对象。
文档对象的虚拟函数OnCloseDocument调用时销毁了主窗口(Windows窗口和MFC窗口对象),同时也导致视、工具条窗口的销毁。
主窗口销毁后,应用程序的主窗口对象为空,故发送WM_QUIT消息结束程序。
2.MDI主窗口的关闭
首先,关闭应用程序的所有文档对象。
文档对象的OnCloseDocument函数关闭文档时,将销毁文档对象对应的文档边框窗口和它的视窗口。
这样,所有的MDI子窗口(包括其子窗口视)被销毁,但应用程序的主窗口还在。
接着,调用DestroyWindow成员函数销毁主窗口自身,DestroyWindow发现被销毁的是应用程序的主窗口,于是发送WM_QUIT消息结束程序。
3.MDI子窗口(文档边框窗口)的关闭
在这种情况下,被关闭的不是主窗口。
判断与该文档边框窗口对应的文档对象是否还被其他一个或者多个文档边框窗口使用,如果是,则仅仅销毁该文档边框窗口(包括其子窗口视);否则,关闭文档,文档对象的OnCloseDocument将销毁该文档边框窗口(包括其子窗口视)。
3.用C语言软件版本命名规则
1.版本命名格式:
说明:
1)主版本号当功能模块有较大的变动,比如增加多个模块或者整体架构发生变化。
此版本号由项目决定是否修改。
以十六进制BCD码表示:
0、…、9。
2)次版本号当功能有一定的增加或变化,比如增加了对权限控制、增加自定义视图等功能。
以及Bug修复或是一些小的变动,要经常发布修订版,时间间隔不限,修复一个严重的bug即可发布一个修订