﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-liupeng0712</title><link>http://www.cppblog.com/liupeng0712/</link><description /><language>zh-cn</language><lastBuildDate>Wed, 15 Apr 2026 00:27:46 GMT</lastBuildDate><pubDate>Wed, 15 Apr 2026 00:27:46 GMT</pubDate><ttl>60</ttl><item><title>TCP/IP网络通信程序设计</title><link>http://www.cppblog.com/liupeng0712/archive/2006/12/17/16567.html</link><dc:creator>行云流水（VC）</dc:creator><author>行云流水（VC）</author><pubDate>Sun, 17 Dec 2006 15:58:00 GMT</pubDate><guid>http://www.cppblog.com/liupeng0712/archive/2006/12/17/16567.html</guid><wfw:comment>http://www.cppblog.com/liupeng0712/comments/16567.html</wfw:comment><comments>http://www.cppblog.com/liupeng0712/archive/2006/12/17/16567.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liupeng0712/comments/commentRss/16567.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liupeng0712/services/trackbacks/16567.html</trackback:ping><description><![CDATA[
		<pre> 用Visual C++4.2中MFC在Windows 95环境下开发的程序实例。

    1 Sockets与Winsock 95

    Winsock 95是在Unix Sockets及Windows Sockets基础上发展起

来的。Sockets原是BSD为了Unix支持互联网通信而设计的4.3BSD Uni

x版本中的API,它采用客户-服务器模式的通信机制,使网络客户方和

服务器方通过Sockets实现网络之间的联接和数据交换;Win dows Soc

kets描述定义了一个Microsoft Windows的网络编程界面,它为Window

s TCP/IP 提供了一个BSD型套接字,除与4.3BSD Unix Sockets完全兼

容外,还包括一个扩充文件,通过一组附加的API实现Windows式(即事

件驱动)的编程风格;而Winsock 95则是在Microso ft Windows 95中

进行网络应用程序设计的接口。Windows 95在Internet支配域中的TC

P /IP协议定义了Winsock 95网络编程规范,溶入了许多新特点。MFC

中提供了相应的CSock et类来实现网络通信。

    2 Sockets编程原理

    Sockets同时支持数据流Sockets和数据报Sockets。

    下面是利用Socket进行通信连接的过程框图。其中图1是面向连

接的时序图,图2是无连接的时序图。

图1

图2

    由图可以看出,客户与服务器的关系是不对称的。对于TCP C/S,

服务器首先启动,然后在某一时刻启动客户与服务器建立连接。服务

器与客户开始都必须调用socket()建立一个套接字socket,然后服务

器调用bind()将套接字与一个本地网络地址捆扎在一起,再调用liste

n()使套接字处于一种被动的准备接收状态,同时规定它的请求队列长

度,之后服务器就可以调用accept()来接收客户连接。客户打开套接

字之后,便可通过调用conne ct()和服务器建立连接。连接建立之后,

客户和服务器之间就可以通过连接发送和接收数据。最后,待数据传

送结束,双方调用closesocket()关闭套接字。对于UDP C/S,客户并不

与服务器建立一个连接,而仅仅给服务器发送一张包含服务器地址的

数据报。相似地,服务器也不从客户端接收一个连接,只是调用函数re

cvfrom,等待从客户端来的数据。依照recvfrom返回的协议地址以及

数据报,服务器就可以给客户送一个应答。

    3 Winsock 95编程方法

    用Visual C++4.2以MFC在Windows 95中实现网络编程,主要就是

利用CSocket类及其如下相关成员函数:

    (1)BOOL Create (UINT nSocketPort=0,int nSocketType=SOCK_

STREAM,long lEve nt=FD_READ|FD_WRITE|FD_OOD|FD_ACCEPT|FD_CON

NECT|FD_CLOSE|,LPCTSTR|lpszSocket Address=NULL

    该函数用来建立Socket。

    (2)BOOL Bind(UINT nSocketPort,LPCTSTR lpszSocketAddess=N

ULL)

    该函数的作用是将Socket端口与网络地址连接起来。

    (3)BOOL Listen(int nConnectionBacklog=5)

    该函数的作用是等待Socket请求。

    (4)Virtual BOOL Accept(CAsyncSocket &amp; rConnected Socket,

Socket,SOCKADDR*  lpSock Addr=NULL,int * lpSock AddrLen=NULL

)

    该函数的作用是取得队列上第一个连接请求并建立一个具有与So

cket相同特性的套接字。

    (5)BOOL Connect (LPCTSTR lpszHostAddress,UINT nHostPort)

    该函数的作用是提出请求。其中,lpszHostAddress和nHostPort

为接受请求进程的网络地址和Socket端口号。

    (6)virtual void Close()该函数的作用是关闭Socket。

    使用以上类及成员函数,按照以下步骤,就可以设计出合适的通信

程序:

    Server:Construct→Creat→Bind→Listen→Accept→Send→Clo

se;

    Client:Constuct→Creat→Connect→Receive→Close。

    4 程序实例

    我们用Visual C++4.2中MFC在Windows 95环境下设计了一个dayt

ime cliont程序,清单如下:

    头文件HEAD.H内容:

    #define IDM_STRAT 200

    #define IDM_EDIT 200

    class Mainwnd:public CFrame Wnd

    {public:Mainwnd();

    afx_msg int OnCreat(LPCREATESTRUCT);

    afx_msg void OnStart(void);

    DECLARE_MESSAGE_MAP();

    private:Cstatic CSStatic;

    CEdit LineEdit;

    CButten StartButton;};

    class PengApp:public CWinApp

    {public:BOOL InitInstance();}

    源程序Client.CPP清单:

    #include&lt;afxwin.h&gt;

    #include&lt;winsock.h&gt;

    #include "head.h"

    const int nPort=13;

    PengApp theApp;

    Main Wnd:Main Wnd()

    {if(!Create (NULL,"Communication Program",WS_OVERLAPPEDW

INDOW,rectDefaul t)) AfxAbort();}

    int Mainwnd:OnCreate(LPCREATESTRUCT)

    {Rect rect;SetRect(&amp; rect,80,50,160,70);

    Create("Host Name:",WS_CHILD|WS_VISIBLE|SS_LEFT,rect,thi

s);

    SetRect(&amp; rect,60,80,180,100);

    LineEdit.Create(WS_CHILD|WS_VISIBLE|WS_DLGFRAME|ES_LEFT,

rect,this,IDM_ED IT);

    SetRect(&amp;rect,100,120,140,140);

    StartButton,Create("start",WS_CHILD|VS_VISIBLE|BS_PUSHBU

TTON,rect,this,I DM_START);

    return 0;}

    BEGIN_MESSAGE_MAP(Main Wnd,CFrameWnd)

    ON_WM_CREATE()

    ON_BN_CLICKED(IDM_START,OnStart)

    END_MESSAGE_MAP()

    BOOL ControlApp:InitInstance()

    {m_pMainWnd=new Main Wnd();

    m_pMainWnd→ShowWindow (m_nCmdShow);

    m_pMainWnd→UpdateWindow();

    return;}

    Void Main Wnd:Onstart(void)

    {CSocket TimeClient;

    if(! AfxSocketInit()) MessageBox("WindowsSocket initial 

failed!","Receiv e",MB_ICONSTOP);

    if(! TimeClient.Create()) MessageBox("ReceiveSocket crea

te failed","Rece ive",MB_I(ON)STOP);

    else TimeClient.connect(strAddr,nPort);

    TimeClient.ReceiveFrom(csReceiveText,csCounts,LineEdit.G

etWinText,nPort)

    MessageBox(TimeClient.csReceiveText);

    TimeClient.Close();}

  </pre>
<img src ="http://www.cppblog.com/liupeng0712/aggbug/16567.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liupeng0712/" target="_blank">行云流水（VC）</a> 2006-12-17 23:58 <a href="http://www.cppblog.com/liupeng0712/archive/2006/12/17/16567.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用VC 6.0实现串行通信的三种方法 </title><link>http://www.cppblog.com/liupeng0712/archive/2006/12/17/16566.html</link><dc:creator>行云流水（VC）</dc:creator><author>行云流水（VC）</author><pubDate>Sun, 17 Dec 2006 15:56:00 GMT</pubDate><guid>http://www.cppblog.com/liupeng0712/archive/2006/12/17/16566.html</guid><wfw:comment>http://www.cppblog.com/liupeng0712/comments/16566.html</wfw:comment><comments>http://www.cppblog.com/liupeng0712/archive/2006/12/17/16566.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liupeng0712/comments/commentRss/16566.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liupeng0712/services/trackbacks/16566.html</trackback:ping><description><![CDATA[---- 摘要： 本文介绍了在Windows平台下串行通信的实现机制，讨论了根据不同的条件用<br /><br />Visual C++ 设计串行通信程序的三种方法，并结合实际，实现对温度数据的接收监控。 <br /><br /><br /><br />---- 在实验室和工业应用中，串口是常用的计算机与外部串行设备之间的数据传输通道，<br /><br />由于串行通信方便易行，所以应用广泛。依据不同的条件实现对串口的灵活编程控制是我们<br /><br />所需要的。 <br /><br /><br /><br />---- 在光学镜片镀膜工艺中，用单片机进行多路温度数据采集控制，采集结果以串行方式进<br /><br />入主机，每隔10S向主机发送一次采样数据，主机向单片机发送相关的控制命令，实现串行数<br /><br />据接收，处理，记录，显示，实时绘制曲线。串行通信程序开发环境为 VC++ 6.0。 <br /><br /><br /><br />---- Windows下串行通信 <br /><br /><br /><br />---- 与以往DOS下串行通信程序不同的是，Windows不提倡应用程序直接控制硬件，而是通过<br /><br />Windows操作系统提供的设备驱动程序来进行数据传递。串行口在Win 32中是作为文件来进行<br /><br />处理的，而不是直接对端口进行操作，对于串行通信，Win 32 提供了相应的文件I/O函数与<br /><br />通信函数，通过了解这些函数的使用，可以编制出符合不同需要的通信程序。与通信设备相<br /><br />关的结构有COMMCONFIG ，COMMPROP，COMMTIMEOUTS，COMSTAT，DCB，MODEMDEVCAPS，<br /><br />MODEMSETTINGS共7个，与通信有关的Windows API函数共有26个，详细说明可参考MSDN帮助文<br /><br />件。以下将结合实例，给出实现串行通信的三种方法。 <br /><br /><br /><br />---- 实现串行通信的三种方法 <br /><br /><br /><br />---- 方法一：使用VC++提供的串行通信控件MSComm 首先，在对话框中创建通信控件，若<br /><br />Control工具栏中缺少该控件，可通过菜单Project --&gt; Add to Project --&gt; Components <br /><br />and Control插入即可，再将该控件从工具箱中拉到对话框中。此时，你只需要关心控件提<br /><br />供的对 Windows 通讯驱动程序的 API 函数的接口。换句话说，只需要设置和监视MSComm控<br /><br />件的属性和事件。 <br /><br /><br /><br />---- 在ClassWizard中为新创建的通信控件定义成员对象（CMSComm m_Serial），通过该对<br /><br />象便可以对串口属性进行设置，MSComm 控件共有27个属性，这里只介绍其中几个常用属性： <br /><br /><br /><br />---- CommPort 设置并返回通讯端口号，缺省为COM1。 <br /><br /><br /><br />---- Settings 以字符串的形式设置并返回波特率、奇偶校验、数据位、停止位。 <br /><br /><br /><br />---- PortOpen 设置并返回通讯端口的状态，也可以打开和关闭端口。 <br /><br /><br /><br />---- Input 从接收缓冲区返回和删除字符。 <br /><br /><br /><br />---- Output 向发送缓冲区写一个字符串。 <br /><br /><br /><br />---- InputLen 设置每次Input读入的字符个数，缺省值为0，表明读取接收缓冲 区中的全部内容。 <br /><br /><br /><br />---- InBufferCount 返回接收缓冲区中已接收到的字符数，将其置0可以清除接收缓 冲区。 <br /><br /><br /><br />---- InputMode 定义Input属性获取数据的方式（为0：文本方式；为1：二进制方式）。 <br /><br /><br /><br />---- RThreshold 和 SThreshold 属性，表示在 OnComm 事件发生之前，接收缓冲区或发送缓冲<br /><br />区中可以接收的字符数。 <br /><br /><br /><br />---- 以下是通过设置控件属性对串口进行初始化的实例： <br /><br /><br /><br />BOOL    CSampleDlg:: PortOpen()<br /><br />{<br /><br />BOOL   m_Opened;<br /><br /> ......<br /><br /> m_Serial.SetCommPort(2);          //  指定串口号<br /><br /> m_Serial.SetSettings("4800,N,8,1");   //  通信参数设置<br /><br /> m_Serial.SetInBufferSize(1024);      //  指定接收缓冲区大小<br /><br /> m_Serial.SetInBufferCount(0);        //  清空接收缓冲区<br /><br /> m_Serial.InputMode(1);             //  设置数据获取方式<br /><br /> m_Serial.SetInputLen(0);            //  设置读取方式<br /><br /> m_Opened=m_Serail.SetPortOpen(1);           //   打开指定的串口<br /><br />       return  m_Opened;<br /><br />   }<br /><br /><br /><br />---- 打开所需串口后，需要考虑串口通信的时机。在接收或发送数据过程中，可能需要监视并<br /><br />响应一些事件和错误，所以事件驱动是处理串行端口交互作用的一种非常有效的方法。使用 <br /><br />OnComm 事件和 CommEvent 属性捕捉并检查通讯事件和错误的值。发生通讯事件或错误时，将<br /><br />触发 OnComm 事件，CommEvent 属性的值将被改变，应用程序检查 CommEvent 属性值并作出相<br /><br />应的反应。在程序中用ClassWizard为CMSComm控件添加OnComm消息处理函数： <br /><br /><br /><br />void  CSampleDlg::OnComm()<br /><br />{<br /><br />  ......<br /><br />  switch(m_Serial.GetCommEvent())<br /><br />  {<br /><br />     case  2:<br /><br />       //  串行口数据接收，处理；<br /><br />   }<br /><br />}<br /><br /><br /><br />---- 方法二：在单线程中实现自定义的串口通信类 <br /><br /><br /><br />---- 控件简单易用，但由于必须拿到对话框中使用，在一些需要在线程中实现通信的应用场合，<br /><br />控件的使用显得捉襟见肘。此时，若能够按不同需要定制灵活的串口通信类将弥补控件的不足，<br /><br />以下将介绍如何在单线程中建立自定义的通信类。 <br /><br /><br /><br />---- 该通信类CSimpleComm需手动加入头文件与源文件，其基类为CObject，大致建立步骤如下： <br /><br /><br /><br />---- (1) 打开串口，获取串口资源句柄 <br /><br /><br /><br />---- 通信程序从CreateFile处指定串口设备及相关的操作属性。再返回一个句柄，该句柄将被用<br /><br />于后续的通信操作，并贯穿整个通信过程。CreateFile()函数中有几个值得注意的参数设置：串口<br /><br />共享方式应设为0，串口为不可共享设备；创建方式必须为OPEN_EXISTING,即打开已有的串口。对<br /><br />于dwFlagAndAttribute参数，对串口有意义的值是FILE_FLAG_OVERLAPPED，该标志表明串口采用异<br /><br />步通信模式，可进行重叠操作；若值为NULL，则为同步通信方式，在同步方式下，应用程序将始终<br /><br />控制程序流，直到程序结束，若遭遇通信故障等因素，将导致应用程序的永久等待，所以一般多采<br /><br />用异步通信。 <br /><br /><br /><br />---- （2）串口设置 <br /><br /><br /><br />---- 串口打开后，其属性被设置为默认值，根据具体需要，通过调用GetCommState(hComm,&amp;dcb)<br /><br />读取当前串口设备控制块DCB（Device Control Block）设置，修改后通过SetCommState(hComm,&amp;dcb)<br /><br />将其写入。再需注意异步读写的超时控制设置， 通过COMMTIMEOUTS结构设置超时，调用<br /><br />SetCommTimeouts(hComm,&amp;timeouts)将结果写入。以下是温度监控程序中串口初始化成员函数： <br /><br /><br /><br />BOOL  CSimpleComm::Open( )<br /><br />     {<br /><br />	  DCB dcb;<br /><br /><br /><br />m_hIDComDev=CreateFile( "COM2", <br /><br />GENERIC_READ | GENERIC_WRITE,<br /><br />0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_<br /><br />NORMAL|FILE_FLAG_OVE    RLAPPED, NULL );        <br /><br />//  打开串口，异步操作<br /><br />if( m_hIDComDev == NULL ) return( FALSE );<br /><br /><br /><br />dcb.DCBlength = sizeof( DCB );<br /><br />GetCommState( m_hIDComDev, &amp;dcb );  //  获得端口默认设置<br /><br />dcb.BaudRate=CBR_4800;<br /><br />dcb.ByteSize=8;<br /><br />dcb.Parity= NOPARITY;<br /><br />dcb.StopBits=(BYTE) ONESTOPBIT;<br /><br />       ...... }<br /><br /><br /><br />---- （3）串口读写操作 <br /><br /><br /><br />---- 主要运用ReadFile（）与WriteFile（）API函数，若为异步通信方式，两函数中最后一个参数<br /><br />为指向OVERLAPPED结构的非空指针，在读写函数返回值为FALSE的情况下，调用GetLastError（）函<br /><br />数，返回值为ERROR_IO_PENDING，表明I/O操作悬挂，即操作转入后台继续执行。此时，可以用<br /><br />WaitForSingleObject()来等待结束信号并设置最长等待时间，举例如下： <br /><br /><br /><br />BOOL   bReadStatus;<br /><br />    bReadStatus = ReadFile( m_hIDComDev, buffer, <br /><br />	dwBytesRead, &amp;dwBytesRead,    &amp;m_OverlappedRead );<br /><br />    if(!bReadStatus)<br /><br />	 {<br /><br />	    if(GetLastError()==ERROR_IO_PENDING)<br /><br />		{<br /><br />       WaitForSingleObject(m_OverlappedRead.hEvent,1000);<br /><br />			return ((int)dwBytesRead);<br /><br />		}<br /><br />		return(0);<br /><br />	 }<br /><br />	 return ((int)dwBytesRead);<br /><br /><br /><br />---- 定义全局变量m_Serial作为新建通信类CSimpleComm的对象，通过调用类的成员函数即可实<br /><br />现所需串行通信功能。与方法一相比，方法二赋予串行通信程序设计较大的灵活性，端口的读写<br /><br />可选择较简单的查询式，或通过设置与外设数据发送时间间隔TimeCycle相同的定时器：<br /><br />SetTimer(1,TimeCycle,NULL)，进行定时读取或发送。 <br /><br /><br /><br />CSampleView:: OnTimer(UINT nIDEvent)<br /><br />     {<br /><br />       char  InputData[30];<br /><br />       m_Serial.ReadData(InputData,30);<br /><br />       // 数据处理<br /><br />     } <br /><br />---- 若对端口数据的响应时间要求较严格，可采用事件驱动I/O读写，Windows定义了9种串口通<br /><br />信事件，较常用的有： <br /><br /><br /><br />---- EV_RXCHAR: 接收到一个字节，并放入输入缓冲区。 <br /><br /><br /><br />---- EV_TXEMPTY: 输出缓冲区中的最后一个字符发送出去。 <br /><br /><br /><br />---- EV_RXFLAG: 接收到事件字符(DCB结构中EvtChar成员)，放入输入缓冲区。 <br /><br /><br /><br />---- 在用SetCommMask()指定了有用的事件后，应用程序可调用WaitCommEvent()来等待事件的发生<br /><br />。SetCommMask(hComm,0)可使WaitCommEvent()中止。 <br /><br /><br /><br />---- 方法三 多线程下实现串行通信 <br /><br /><br /><br />---- 方法一，二适用于单线程通信。在很多工业控制系统中，常通过扩展串口连接多个外设，各外<br /><br />设发送数据的重复频率不同，要求后台实时无差错捕捉，采集，处理，记录各端口数据，这就需要<br /><br />在自定义的串行通信类中创建端口监视线程，以便在指定的事件发生时向相关的窗口发送通知消息。 <br /><br /><br /><br />---- 线程的基本概念可详见VC++参考书目，Windows内部的抢先调度程序在活动的线程之间分配CPU<br /><br />时间，Win 32 区分两种不同类型的线程，一种是用户界面线程UI（User Interface Thread）,它包<br /><br />含消息循环或消息泵，用于处理接收到的消息；另一种是工作线程（Work Thread），它没有消息循<br /><br />环，用于执行后台任务。用于监视串口事件的线程即为工作线程。 <br /><br /><br /><br />---- 多线程通信类的编写在端口的配置，连接部分与单线程通信类相同，在端口配置完毕后，最重<br /><br />要的是根据实际情况，建立多线程之间的同步对象，如信号灯，临界区，事件等，相关细节可参考<br /><br />VC++ 中的同步类。 <br /><br /><br /><br />---- 一切就绪后即可启动工作线程： <br /><br /><br /><br />CWinThrea *CommThread = AfxBegin<br /><br />Thread(CommWatchThread,  // 线程函数名<br /><br /> (LPVOID) m_pTTYInfo,                       // 传递的参数<br /><br /> THREAD_PRIORITY_ABOVE_NORMAL,       // 设置线程优先级<br /><br />  (UINT) 0,                                  //  最大堆栈大小<br /><br />  (DWORD) CREATE_SUSPENDED ,           //  创建标志<br /><br /> (LPSECURITY_ATTRIBUTES) NULL);         //  安全性标志<br /><br /><br /><br />---- 同时，在串口事件监视线程中： <br /><br /><br /><br />if(WaitCommEvent(pTTYInfo-&gt;idComDev,&amp;dwEvtMask,NULL))<br /><br />		{<br /><br />	if((dwEvtMask  &amp; pTTYInfo-&gt;dwEvtMask )== pTTYInfo-&gt;dwEvtMask)<br /><br />	{<br /><br />	 WaitForSingleObject(pTTYInfo-&gt;hPostEvent,0xFFFFFFFF);<br /><br />      ResetEvent(pTTYInfo-&gt;hPostEvent);    // 置同步事件对象为非信号态<br /><br />	   ::PostMessage(CSampleView,ID_COM1_DATA,0,0);  // 发送通知消息<br /><br />			}<br /><br />		}<br /><br />---- 用PostMessage()向指定窗口的消息队列发送通知消息，相应地，需要在该窗口建立消息与成<br /><br />员函数间的映射，用ON_MESSAGE将消息与成员函数名关联。 <br /><br /><br /><br />BEGIN_MESSAGE_MAP(CSampleView, CView)<br /><br /> //{{AFX_MSG_MAP(CSampleView)<br /><br />ON_MESSAGE(ID_COM1_DATA, OnProcessCom1Data)  <br /><br />	ON_MESSAGE(ID_COM2_DATA, OnProcessCom2Data)  <br /><br />.....<br /><br />//}}AFX_MSG_MAP<br /><br />END_MESSAGE_MAP()<br /><br /><br /><br />---- 然后在各成员函数中完成对各串口数据的接收处理，但必须保证在下一次监测到有数据到来之<br /><br />前，能够完成所有的中间处理工作。否则将造成数据的捕捉错误。 <br /><br /><br /><br />---- 多线程的实现可以使得各端口独立，准确地实现串行通信，使串口通信具有更广泛的灵活性与<br /><br />严格性，且充分利用了CPU时间。但在具体的实时监控系统中如何协调多个线程，线程之间以何种方<br /><br />式实现同步也是在多线程串行通信程序实现的难点。 <br /><br /><br /><br />---- 以VC++ 6.0 为工具，实现串行通信的三种方法各有利弊， <br /><br /><br /><br /><br /><br /><br /><br />---- 根据不同需要，选择合适的方法，将达到事半功倍的效果。在温度监控系统中，笔者采用了方<br /><br />法二，在Window 98 ,Windows 95 上运行稳定，取得了良好的效果。 <br /><br /><br /><br /><img src ="http://www.cppblog.com/liupeng0712/aggbug/16566.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liupeng0712/" target="_blank">行云流水（VC）</a> 2006-12-17 23:56 <a href="http://www.cppblog.com/liupeng0712/archive/2006/12/17/16566.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言高效编程的几招</title><link>http://www.cppblog.com/liupeng0712/archive/2006/12/17/16565.html</link><dc:creator>行云流水（VC）</dc:creator><author>行云流水（VC）</author><pubDate>Sun, 17 Dec 2006 15:53:00 GMT</pubDate><guid>http://www.cppblog.com/liupeng0712/archive/2006/12/17/16565.html</guid><wfw:comment>http://www.cppblog.com/liupeng0712/comments/16565.html</wfw:comment><comments>http://www.cppblog.com/liupeng0712/archive/2006/12/17/16565.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liupeng0712/comments/commentRss/16565.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liupeng0712/services/trackbacks/16565.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="TEXT-ALIGN: left" align="left">
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">摘要：</span>
				</b>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">以凌阳单片机为例详细介绍</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">μC/OS-II</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">的移植方法；重点讲解在系统移植过程中一些难以理解的概念，并首次实现了</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">μC/OS-II</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">在凌阳</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">SPCE061A</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">单片机上的移植。</span>
		</p>
		<p class="MsoNormal" style="TEXT-ALIGN: left" align="left">
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">关键词：</span>
				</b>
		</p>
		<p class="MsoNormal" style="TEXT-ALIGN: left" align="left">
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">引</span>
				</b>
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						</span>
				</b>
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">言：</span>
				</b>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　<b>　</b>编写高效简洁的</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">C</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">语言代码，是许多软件工程师追求的目标。本文就工作中的一些体会和经验做相关的阐述，不对的地方请各位指教。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">第</span>
				</b>
				<b>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">1</span>
				</b>
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">招：以空间换时间</span>
				</b>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　计算机程序中最大的矛盾是空间和时间的矛盾，那么，从这个角度出发逆向思维来考虑程序的效率问题，我们就有了解决问题的第</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">1</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">招</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">——</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">以空间换时间。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">例如：字符串的赋值。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">A</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">，通常的办法：</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />#define LEN 32<br />char string1 [LEN];<br />memset (string1,0,LEN);<br />strcpy (string1,“This is a example!!”</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">）</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">;<br /></span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">B</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">：</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />const char string2[LEN] =“This is a example!”;<br />char * cp;<br />cp = string2 ; <br />(</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">使用的时候可以直接用指针来操作。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">)<br /><br /></span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　从上面的例子可以看出，</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">A</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">和</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">B</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">的效率是不能比的。在同样的存储空间下，</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">B</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">直接使用指针就可以操作了，而</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">A</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">需要调用两个字符函数才能完成。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">B</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">的缺点在于灵活性没有</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">A</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">好。在需要频繁更改一个字符串内容的时候，</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">A</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">具有更好的灵活性；如果采用方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">B</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">，则需要预存许多字符串，虽然占用了大量的内存，但是获得了程序执行的高效率。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　如果系统的实时性要求很高，内存还有一些，那我推荐你使用该招数。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　该招数的变招</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">——</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">使用宏函数而不是函数。举例如下：</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">C</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">：</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />#define bwMCDR2_ADDRESS 4<br />#define bsMCDR2_ADDRESS 17<br />int BIT_MASK(int __bf) <br />{<br />return ((1U &lt;&lt; (bw ## __bf)) - 1) &lt;&lt; (bs ## __bf);<br />}<br />void SET_BITS(int __dst, int __bf, int __val)<br />{<br />__dst = ((__dst) &amp; ~(BIT_MASK(__bf))) | \<br />(((__val) &lt;&lt; (bs ## __bf)) &amp; (BIT_MASK(__bf))))<br />}<br /><br />SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);<br /></span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">D</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">：</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />#define bwMCDR2_ADDRESS 4<br />#define bsMCDR2_ADDRESS 17<br />#define bmMCDR2_ADDRESS BIT_MASK(MCDR2_ADDRESS)<br />#define BIT_MASK(__bf) (((1U &lt;&lt; (bw ## __bf)) - 1) &lt;&lt; (bs ## __bf))<br />#define SET_BITS(__dst, __bf, __val) \<br />((__dst) = ((__dst) &amp; ~(BIT_MASK(__bf))) | \<br />(((__val) &lt;&lt; (bs ## __bf)) &amp; (BIT_MASK(__bf))))</span>
		</p>
		<p class="MsoNormal" style="TEXT-ALIGN: left" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);<br /><br /></span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　函数和宏函数的区别就在于，宏函数占用了大量的空间，而函数占用了时间。大家要知道的是，函数调用是要使用系统的栈来保存数据的，如果编译器里有栈检查选项，一般在函数的头会嵌入一些汇编语句对当前栈进行检查；同时，</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">CPU</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">也要在函数调用时保存和恢复当前的现场，进行压栈和弹栈操作，所以，函数调用需要一些</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">CPU</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">时间。而宏函数不存在这个问题。宏函数仅仅作为预先写好的代码嵌入到当前程序，不会产生函数调用，所以仅仅是占用了空间，在频繁调用同一个宏函数的时候，该现象尤其突出。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">D</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法是我看到的最好的置位操作函数，是</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">ARM</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">公司源码的一部分，在短短的三行内实现了很多功能，几乎涵盖了所有的位操作功能。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">C</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法是其变体，其中滋味还需大家仔细体会。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">第</span>
				</b>
				<b>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">2</span>
				</b>
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">招：数学方法解决问题</span>
				</b>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　现在我们演绎高效</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">C</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">语言编写的第二招</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">——</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">采用数学方法来解决问题。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　数学是计算机之母，没有数学的依据和基础，就没有计算机的发展，所以在编写程序的时候，采用一些数学方法会对程序的执行效率有数量级的提高。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">举例如下，求</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥"> 1~100</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">的和。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">E<br />int I , j;<br />for (I = 1 ;I&lt;=100; I ++</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">）</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">{<br />j += I;<br />}<br /></span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">F<br />int I;<br />I = (100 * (1+100)) / 2<br /><br /></span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　这个例子是我印象最深的一个数学用例，是我的计算机启蒙老师考我的。当时我只有小学三年级，可惜我当时不知道用公式</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥"> N×</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">（</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">N+1</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">）</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">/ 2 </span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">来解决这个问题。方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">E</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">循环了</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">100</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">次才解决问题，也就是说最少用了</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">100</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">个赋值，</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">100</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">个判断，</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">200</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">个加法（</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">I</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">和</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">j</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">）；而方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">F</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">仅仅用了</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">1</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">个加法，</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">1</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">次乘法，</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">1</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">次除法。效果自然不言而喻。所以，现在我在编程序的时候，更多的是动脑筋找规律，最大限度地发挥数学的威力来提高程序运行的效率。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">第</span>
				</b>
				<b>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">3</span>
				</b>
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">招：使用位操作</span>
				</b>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　实现高效的</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">C</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">语言编写的第三招</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">——</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">使用位操作，减少除法和取模的运算。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　在计算机程序中，数据的位是可以操作的最小数据单位，理论上可以用</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">“</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">位运算</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">”</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">来完成所有的运算和操作。一般的位操作是用来控制硬件的，或者做数据变换使用，但是，灵活的位操作可以有效地提高程序运行的效率。举例如下：</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">G<br />int I,J;<br />I = 257 /8;<br />J = 456 % 32;<br /></span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">H<br />int I,J;<br />I = 257 &gt;&gt;3;<br />J = 456 - (456 &gt;&gt; 4 &lt;&lt; 4);<br /><br /></span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　在字面上好像</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">H</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">比</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">G</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">麻烦了好多，但是，仔细查看产生的汇编代码就会明白，方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">G</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">调用了基本的取模函数和除法函数，既有函数调用，还有很多汇编代码和寄存器参与运算；而方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">H</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">则仅仅是几句相关的汇编，代码更简洁，效率更高。当然，由于编译器的不同，可能效率的差距不大，但是，以我目前遇到的</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">MS C ,ARM C </span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">来看，效率的差距还是不小。相关汇编代码就不在这里列举了。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">运用这招需要注意的是，因为</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">CPU</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">的不同而产生的问题。比如说，在</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">PC</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">上用这招编写的程序，并在</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">PC</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">上调试通过，在移植到一个</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">16</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">位机平台上的时候，可能会产生代码隐患。所以只有在一定技术进阶的基础下才可以使用这招。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">第</span>
				</b>
				<b>
						<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">4</span>
				</b>
				<b>
						<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">招：汇编嵌入</span>
				</b>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　高效</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">C</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">语言编程的必杀技，第四招</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">——</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">嵌入汇编。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">“</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">在熟悉汇编语言的人眼里，</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">C</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">语言编写的程序都是垃圾</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">”</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">。这种说法虽然偏激了一些，但是却有它的道理。汇编语言是效率最高的计算机语言，但是，不可能靠着它来写一个操作系统吧</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">?</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">所以，为了获得程序的高效率，我们只好采用变通的方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥"> ——</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">嵌入汇编，混合编程。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　举例如下，将数组一赋值给数组二</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">,</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">要求每一字节都相符。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />char string1[1024],string2[1024];<br /></span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">I<br />int I;<br />for (I =0 ;I&lt;1024;I++)<br />*(string2 + I) = *(string1 + I)<br /></span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">J<br />#ifdef _PC_<br />int I;<br />for (I =0 ;I&lt;1024;I++)<br />*(string2 + I) = *(string1 + I);<br />#else<br />#ifdef _ARM_<br />__asm<br />{ <br />MOV R0,string1<br />MOV R1,string2<br />MOV R2,#0<br />loop:<br />LDMIA R0!, [R3-R11]<br />STMIA R1!, [R3-R11]<br />ADD R2,R2,#8<br />CMP R2, #400<br />BNE loop<br />}<br />#endif<br /><br /></span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">I</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">是最常见的方法，使用了</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">1024</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">次循环；方法</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">J</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">则根据平台不同做了区分，在</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">ARM</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">平台下，用嵌入汇编仅用</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">128</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">次循环就完成了同样的操作。这里有朋友会说，为什么不用标准的内存拷贝函数呢</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">?</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">这是因为在源数据里可能含有数据为</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">0</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">的字节，这样的话，标准库函数会提前结束而不会完成我们要求的操作。这个例程典型应用于</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">LCD</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">数据的拷贝过程。根据不同的</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">CPU</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">，熟练使用相应的嵌入汇编，可以大大提高程序执行的效率。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　虽然是必杀技，但是如果轻易使用会付出惨重的代价。这是因为，使用了嵌入汇编，便限制了程序的可移植性，使程序在不同平台移植的过程中，卧虎藏龙，险象环生！同时该招数也与现代软件工程的思想相违背，只有在迫不得已的情况下才可以采用。切记，切记。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">
						<br />
						<br />
				</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">　　使用</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: ˎ̥">C</span>
				<span style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: 宋体">语言进行高效率编程，我的体会仅此而已。在此以本文抛砖引玉，还请各位高手共同切磋。希望各位能给出更好的方法，大家一起提高我们的编程技巧。</span>
		</p>
<img src ="http://www.cppblog.com/liupeng0712/aggbug/16565.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liupeng0712/" target="_blank">行云流水（VC）</a> 2006-12-17 23:53 <a href="http://www.cppblog.com/liupeng0712/archive/2006/12/17/16565.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>