??xml version="1.0" encoding="utf-8" standalone="yes"?>综合久久久久久中文字幕亚洲国产国产综合一区首 ,国产伊人久久,国内精品久久久久影院老司http://www.shnenglu.com/tbwshc/tbwzh-cnWed, 07 May 2025 20:13:02 GMTWed, 07 May 2025 20:13:02 GMT60操作pȝ讑֤场景如何切换http://www.shnenglu.com/tbwshc/archive/2013/09/11/203179.htmltbwshctbwshcWed, 11 Sep 2013 08:34:00 GMThttp://www.shnenglu.com/tbwshc/archive/2013/09/11/203179.htmlhttp://www.shnenglu.com/tbwshc/comments/203179.htmlhttp://www.shnenglu.com/tbwshc/archive/2013/09/11/203179.html#Feedback0http://www.shnenglu.com/tbwshc/comments/commentRss/203179.htmlhttp://www.shnenglu.com/tbwshc/services/trackbacks/203179.html从一个Q务{变到另一个Q务的实际q程叫作讑֤场景切换。因备场景是处理器专用的Q实现设备场景切换的实现也是q样。那意味着它L要用汇编来写。与其向你展C我在ADEOS 中用的80x86 专用的汇~代码,不如我用一U类C 的伪代码来展C备场景切?a style="color: #000000" >tb例程?br />void
contextSwitch(PContext pOldContext, PContext pNewContext)
{
if(saveContext(pOldContext))
{
//
// Restore new context only on a nonzero exit from saveContext().
//
restoreContext(pNewContext);
// This line is never executed!
}
// Instead, the restored task continues to execute at this point.
}

例程 contextSwitch()实际上是被调度程序凋用,而调度程序又在那此终止中断的tbpȝ调用中被调用Q因此它不一定在q里l止中断。此外,׃调用调度E序的操作系l调用是用高U语a写的Q所以大部分q行d的寄存器已经被保存到它自己当地的栈中了。这减少了例EsaveContext()和restoreContext()需要做的工作。它们只需要关心指令指针,栈指针以及标志位的保存。例E?contextSwitch()的实际行为是很难仅仅通过看前面的代码来理解的。大部分的Y件开发者以q箋的方式思考问题,认ؓ每一行代码会紧接着上一条代码破执行。然而,q个代码实际为ƈ行地执行了两ơ。当一个Q务(CQ务)转变到运行状态,另一个(旧Q务)必须同时q回到就l状态。想一下新d当它在restoreContext()代码中被恢复的时候就会明白。无论新d以前做什么,它在saveContext 代码里L醒着?#8212;—因ؓq就是它的指令存攄地方。新d如何知道它是否是W一ơ(也就是,在准备休眠的q程Q或者是W二ơ(醒来的过E)从saveContext()中出来的呢?它确实需要知道这个差别,因此我不得不用一U有炚w蔽的Ҏ来实现saveContext()。例EsaveContext()不是保存了准的目前的指令指针。实际上是保存了一些指令前面的地址。那P当保存的讑֤场景恢复的时候,E序从saveContext 中另一个下同的点l。这也得saveContext 可能q回不同的|当Q务要休眠的时候ؓ非零Q当d唤v的时候ؓ零。例EcontextSwitch()利用q个q回的值来军_是否调用restoreContext()。如果不q行q个,那么与这个新d相关的代码永q不会执行?/p>

我知道这可能是一个复杂的事g序列Q因此我在图8-3 中说明了整个的过E?/p>

tbwshc 2013-09-11 16:34 发表评论
]]>
操作pȝd调度机制http://www.shnenglu.com/tbwshc/archive/2013/09/05/203033.htmltbwshctbwshcThu, 05 Sep 2013 08:58:00 GMThttp://www.shnenglu.com/tbwshc/archive/2013/09/05/203033.htmlhttp://www.shnenglu.com/tbwshc/comments/203033.htmlhttp://www.shnenglu.com/tbwshc/archive/2013/09/05/203033.html#Feedback0http://www.shnenglu.com/tbwshc/comments/commentRss/203033.htmlhttp://www.shnenglu.com/tbwshc/services/trackbacks/203033.htmltbd调度器选择新的dq行的时候会用到Qp 的D大,表示权限高Q?br />TaskId Task::nextId = 0
/**************************************************************
*
* Method : Task()
*
* Description : Create a new task and initialize its state.
*
* Notes :
*
* Returns :
*
**************************************************************/
Task:Task(void (*function)(), Priority p, int stackSize)
{
stackSize /= sizeof(int); //Convert bytes to words.
enterCS(); //Critical Section Begin
//
// Initialize the task-specific data.
//
if = Task::nextId++;
state = Ready;
priority = p;
entryPoint = function;
pStack = new int[stackSize];
pNext = NULL;
//
// Initialize the processor context.
//
contextInit(&context, run, this, pStack + stackSize);
//
// Insert the task into the ready list.
//
os.readyList.insert(this);
os.schedule(); // Scheduling Point
exitCS(); // Critical Section End
} /* Task() */
注意q个例程的功能块被两个函?enterCS()和exitCS()的调用包围。在q些调用之间的代码块叫作tb临界区(critical sectionQ。界区是一个程序必d整执行的一部分。也是_l成q一个部分的指o必须没有中断地按照顺序执行。因Z断可能随时发生,保证不受C断的唯一办法是在执行关键区期间止中断。因此在关键区的开始调用enterCS 以保存中断的允许状态以及禁止进一步的中断。在关键区尾部调用exitCS 以恢复前面保存的中断调用。我们会看到在下面每一个例E中都应用了同样的技巧?br />在前面代码中Q有几个在构造函数里调用的其他例E,但是在这里我没有I间列出。它们是contextInit()和os.readyList.insert()例程。例EcontextInit()ZQ务徏立了初始的设备场景。这个例E必定是处理器专用的Q因此是用汇~语a写的?br />contextInit()有四个参数。第一个是一个指向待初始比的讑֤场景数据l构指针。第二个是一个指向启动函数的指针。这是一个特D的ADEOS 函数Q叫作run()Q它被用来启动一个Q务,q且如果以后相关的函数退ZQ它被用来做其后的清理工作。第三个参数是一个指向新d对象的指针。这个参数被传递给run()Q因此相关的dp够被启动。第四个和最后一个参数是指向CQ务栈的指针?br />另一个函数调用是 os.readyList.insert()。这个函数把CQ务加入到操作pȝ内部的就lQ务列表中。readyList 是一个TaskList cd的对象。这个类是那些具有insert()和remove()两个Ҏ的Q务(按照优先U排序)的链表。感兴趣的读者如果想知道q些函数是如何实现的应该下载和研究其ADEOS 的源代码。你在下面的讨Z了解到更多有兛_l列表的问题?img src ="http://www.shnenglu.com/tbwshc/aggbug/203033.html" width = "1" height = "1" />

tbwshc 2013-09-05 16:58 发表评论
]]>
操作pȝ历史和目?/title><link>http://www.shnenglu.com/tbwshc/archive/2013/09/05/203032.html</link><dc:creator>tbwshc</dc:creator><author>tbwshc</author><pubDate>Thu, 05 Sep 2013 08:46:00 GMT</pubDate><guid>http://www.shnenglu.com/tbwshc/archive/2013/09/05/203032.html</guid><wfw:comment>http://www.shnenglu.com/tbwshc/comments/203032.html</wfw:comment><comments>http://www.shnenglu.com/tbwshc/archive/2013/09/05/203032.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/tbwshc/comments/commentRss/203032.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tbwshc/services/trackbacks/203032.html</trackback:ping><description><![CDATA[<p>在早期的计算ZQ没有操作系l一_应用E序开发h员都要对处理器(CPUQ和gq行dd的控制。实际上Q第一个操作系l的诞生Q就是ؓ了提供一个虚拟的gq_Q以方便E序员开发。ؓ了实现这个目标,操作pȝ只需要提供一些较为松散的函数、例E?#8212;—好像现在的软g库一?#8212;—以便于对g讑֤q行重置、读取状态、写入指令之cȝ操作。现代的操作pȝ则在单处理器上加入了多Q务机Ӟ每个d都是一个Y件模块,可以是相互独立的。嵌入式的Y件经常是可以划分成小的互相独立的模块。例如,W五?#8220;接触g”讲到的打?strong><a style="color: #000000" ><strong>tb</strong></a></strong>׃n讑֤包含三个不同的软gdQ?br />􀂋 d 1Q从计算机的串行口A 接收数据<br />􀂋 d 2Q从计算机的串行口B 接收数据<br />􀂋 d 3Q格式化数据q输送到计算机的q行口(打印机就q接在ƈ行口Q?br />q些d的划分提供了一个很关键的Y件抽象概念,q得嵌入式操作pȝ的设计和实现更加ҎQ源E序也更易于理解和维护。通过把大的程序进行模块化划分Q程序员可以集中_֊克服pȝ开发过E中的关键问题?/p> <p>坦言之,一个操作系lƈ不是嵌入式或其它计算机系l的必需的组Ӟ它所能做的,也是像时用程序要实现的功能一栗本书中的所有例子都说明了这一炏V应用程序执行v来,都是从main 开始,然后q入pȝ调用、运行、结束。这与系l中只有一个Q务是一L。对于应用程序来_仅仅是实CLED q行闪烁Q这是操作pȝ的主要功用(屏蔽了很多复杂的操作Q?/p> <p>如果你以前没作过Ҏ作系l的研究Q那么,在这里得提醒一下,操作pȝ是非常复杂的?a style="color: #000000" ><strong>tb</strong></a>操作pȝ的厂商肯定是想你相信,他们是唯一能生产出功能强大又易用的操作pȝ的科学家。但是,我也要告诉你Q这q不是根困难的。实际上嵌入式操作系l要比桌面操作系l更Ҏ~写Q所需的模块和功能更ؓy、更易于实现。一旦明了要实C功能Qƈ有一定的实现技能,你将会发玎ͼ开发一个操作系lƈ不比开发嵌入式软g艰难多少?/p> <p>嵌入式操作系l很,因ؓ它可以缺很多桌面操作系l的功能。例如,嵌入式操什pȝ很少有硬盘或囑Ş界面Q因此,嵌入式操作系l可以下需要文件系l和囑Ş用户接口。而且Q一般来_是单用户pȝQ所以多用户操作pȝ的安全特性也可以省去了。上面所说的各种性能Q都可以作ؓ嵌入式操作系l的一部分Q但不是必须的?/p><img src ="http://www.shnenglu.com/tbwshc/aggbug/203032.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tbwshc/" target="_blank">tbwshc</a> 2013-09-05 16:46 <a href="http://www.shnenglu.com/tbwshc/archive/2013/09/05/203032.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>应用E序的概q?/title><link>http://www.shnenglu.com/tbwshc/archive/2013/08/19/202640.html</link><dc:creator>tbwshc</dc:creator><author>tbwshc</author><pubDate>Mon, 19 Aug 2013 03:49:00 GMT</pubDate><guid>http://www.shnenglu.com/tbwshc/archive/2013/08/19/202640.html</guid><wfw:comment>http://www.shnenglu.com/tbwshc/comments/202640.html</wfw:comment><comments>http://www.shnenglu.com/tbwshc/archive/2013/08/19/202640.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/tbwshc/comments/commentRss/202640.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tbwshc/services/trackbacks/202640.html</trackback:ping><description><![CDATA[<p>在这一章里Q我试图把到目前为止所有我们讨的单元合在一P使之成ؓ一个完整的嵌入式的应用E序。在q里我没有把很多新的素材加入到讨ZQ因此本章主要是描述其中l出的代码。我的目的是描述q个应用E序的结构和它的源代码,通过q种方式使你对它不再感到奇。完成这一章以后,你应该对于示例程序有一个完整的理解Qƈ且有能力开发自q嵌入式应用程序。应用程序的概述</p> <p>我们要讨论的这个应用程序不比其他大部分<strong><a style="color: #000000" ><strong>tb</strong></a></strong>~程书籍中找到的“HelloQWorld”例子更复杂。它是对于嵌入式软g开发的一个实证,因此q个例子是出现在书的l尾而不是开始。我们不得不逐渐地徏立我们的道\通向大部分书c甚x高语言~译器认为是理所当然的计^台?/p> <p>一旦你能写“Hello, World”E序Q你的嵌入式q_开始着上去很像M其他~程环境。但是,嵌入式Y件开发过E中最困难的部?#8212;—使自q悉硬Ӟ为它建立一个Y件开发的q程Q连接到具体的硬件设?#8212;—q在后面呢。最后,你能够把你的力量集中于算法和用户界面Q这是由你要开发的产品来确定的。很多情况下Q这些程序的高斚w可以在其他的计算机^C开发,和我们一直在讨论的低U的嵌入式Y件开发同时进行,q且只要把高U部分导入嵌入式pȝ一ơ,两者就都完成了?/p> <p>?9-1 包含了一?#8220;Hello, World!”应用E序的高U的C意图。这个应用程序包括三个设备驱动程序,ADEOS 操作pȝ和两个ADEOS d。第一个Q务以每秒10Hz 的速度切换Arcom 板上的红色指C灯。第二个每隔10 U钟向主机或是连接到位子串口上的哑终端发送字W串“HelloQWOrldQ?#8221;。这两个d之外Q图中还有三个设备的驱动E序。这些驱动程序分别控制着Arcom 板子的指C灯、时钟以及串行端口。虽焉常把设备驱动画在操作系l的下面Q但是我把它们三个和操作pȝ攑֜同一个别,是ؓ了着重说明它们事实上依赖于ADEOS 比ADEOS 依赖于它们更多。实际上QADEOS 嵌入式操作系l甚至不知道Q或者说下关心)q些讑֤驱动是否存在于系l之中。这是嵌入式操作pȝ中设备驱动程序和其他g专用软g的共性?/p> <p>E序 main()的实现如下所C。这D代码简单地创造厂两个dQ?strong><a style="color: #000000" ><strong>tb</strong></a></strong>启动了操作系l的日程表。在q样一个高的别上Q代码的含义是不a而喻的。事实上、我们已l在上一章中讨论了类似的代码?/p> <p>#include "adeos.h"<br />void flashRed(void);<br />void helloWorld(void);<br />/*<br />* Create the two tasks.<br />*/<br />Task taskA(flashRed, 150, 512);<br />Task taskB(helloWorld, 200, 512);<br />/****************************************************<br />*<br />* Function : main()<br />*<br />* Description : This function is responsible for starting the ADEOS scheduler<br />only.<br />*<br />* Notes :<br />*<br />* Returns : This function will never return!<br />*<br />****************************************************/<br />void<br />main(void)<br />{<br />os.start();<br />// This point will never be reached.<br />} /* main() */</p><img src ="http://www.shnenglu.com/tbwshc/aggbug/202640.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tbwshc/" target="_blank">tbwshc</a> 2013-08-19 11:49 <a href="http://www.shnenglu.com/tbwshc/archive/2013/08/19/202640.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>减小代码的大?/title><link>http://www.shnenglu.com/tbwshc/archive/2013/07/23/202059.html</link><dc:creator>tbwshc</dc:creator><author>tbwshc</author><pubDate>Tue, 23 Jul 2013 09:21:00 GMT</pubDate><guid>http://www.shnenglu.com/tbwshc/archive/2013/07/23/202059.html</guid><wfw:comment>http://www.shnenglu.com/tbwshc/comments/202059.html</wfw:comment><comments>http://www.shnenglu.com/tbwshc/archive/2013/07/23/202059.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/tbwshc/comments/commentRss/202059.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tbwshc/services/trackbacks/202059.html</trackback:ping><description><![CDATA[<p>正如我早先说的那P当问题归l于减小代码的大的时候,你最好让~译器ؓ你做qg事。然而,如果处理后的E序代码对于你可得的只读存贮器仍然太大了Q还有几U技术你可以用来q一步减体E序的大。在本节中,自动的和人工的代码优化我们都要讨论?br />当然Q墨菲法则指出,W一ơ你启用~译器的优化Ҏ后Q你先前的工作程序会H然失效Q也许自动优化最臭名昭著的是“ȝ删除”。这U优化会删除那些~译器相信是多余的或者是不相关的代码Q比如,把零和一个变量相加不需要Q何的计算旉。但是你可能q是希望如果E序代码执行?a style="color: #000000" >tb</a>~译器不了解的函敎ͼ~译器能够生那?#8220;不相?#8221;的指C?br />比如Q下面这D늻出的代码Q大部分优化~译器会去除W一条语句,因ؓ*pControl 在重?W三?之前没有使用q:<br />*pControl = DISABLE;<br />*pData = 'a';<br />*pCotrol = ENABLE;<br />但是如果 pControl 和pData 实际上是指向内存映像讑֤寄存器的指针怎么?q种情况下,外设在这个字节的数据写入之前接收不到DISABLE 的命令。这可能会潜在地毁坏处理器和q个外设之间的所有未来的交互作用。ؓ了你避免这U问题,你必ȝ关键?#8220;volatile”声明所有指向内存映像设备寄存器的指针和U程之间(或者是一个线E和一个中断服务程序之?׃n的全局变量。你只要漏掉了它们中的一个,墨菲法则׃在你的工E的最后几天里回来Q搅得你心神不宁。我保证?br />——————————————————————————————————<br />警告Q千万不要误以ؓE序优化后的行ؓ会和未优化时的一栗你必须在每一ơ新的优化后完全重新试你的软gQ以保它的行ؓ没有发生改变?br />——————————————————————————————————<br />更糟p的是,或者退一步说Q调试一个优化过的程序是富有挑战性的。启用了~译器的优化后,在源代码中的一行和实现q行代码的那l处理器指o之间的关联关pd得更加微׃。那些特定的指o可能被移动或者拆分开来,或者两个类似的代码可能现在q一个共同的实现。实际上Q?a style="color: #000000" >tb</a>高语言E序的有些行可能完全从程序中去除?正如在前面例子里那样)。结果,你可能无法在E序特定的一行上讄一个断Ҏ者无法研I一个感兴趣变量的倹{?/p> <p>一旦你使用了自动优化,q里有一些关于用手工的办法进一步减代码大的技巧?/p> <p>避免使用标准库例E?br />Z减少你的E序的大,你所能做的最好的一件事情就是避免用大的标准库例程。很多最大的库例E代h贵,只是因ؓ它们设法处理所有可能的情况。你自己有可能用更少的代码实C个子功能。比如,标准C 的库中的spintf例程是出了名的大。这个庞大代码中有相当一部分是位于它所依赖的QҎ处理例程。但是如果你不需要格式化昄点数?%f 或?d)Q那么你可以写你自己的sprintf 的整C用版本,q且可以节省几千字节的代码空间。实际上Q一些标准C 的库(q让我想起Cygnus 的newlib)里恰好包含了q样一个函敎ͼ叫作sprintf?/p> <p>本地字长<br />每一个处理器都有一个本地字长,q且ANSI C 和C++标准规定数据cdint必须L对应到那个字ѝ处理更或者更大的数据cd有时需要用附加的机器语言指o。在你的E序中通过可能的一致用int cdQ你也许能够从你的程序中削减宝贵的几癑֭节?/p> <p>goto 语句<br />像对待全局变量一P好的软g工程实践规定反对使用q项技术。但是危急的时候,goto 语句可以用来去除复杂的控制结构或者共享一块经帔R复的代码?br />除了q些技术以外,在前一部分介绍的几U方法可能也会有帮助Q特别是查询表、手工编写汇~、寄存器变最以及全局变量。在q些技术之中,利用手工~写汇编通常可以得到代码最大幅度的减少量?br /></p><img src ="http://www.shnenglu.com/tbwshc/aggbug/202059.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tbwshc/" target="_blank">tbwshc</a> 2013-07-23 17:21 <a href="http://www.shnenglu.com/tbwshc/archive/2013/07/23/202059.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>优化你的代码http://www.shnenglu.com/tbwshc/archive/2013/07/23/202058.htmltbwshctbwshcTue, 23 Jul 2013 09:19:00 GMThttp://www.shnenglu.com/tbwshc/archive/2013/07/23/202058.htmlhttp://www.shnenglu.com/tbwshc/comments/202058.htmlhttp://www.shnenglu.com/tbwshc/archive/2013/07/23/202058.html#Feedback0http://www.shnenglu.com/tbwshc/comments/commentRss/202058.htmlhttp://www.shnenglu.com/tbwshc/services/trackbacks/202058.html事情应该可能简化,而不只是单一点点Q一爱因斯坦

虽然使Y件正的工作好像应该是一个工E合乎逻辑的最后一个步骤,但是在嵌入式的系l的开发中Q情况ƈ不Lq样的。出于对低hpd产品的需要,g的设计者需要提供刚好够的存储器和完成工作的处理能力。当Ӟ在工E的软g开发阶D,使程序正的工作是很重要的。ؓ此,通常需要一个或者更多的开发电路板Q有的有附加的存贮器Q有的有更快的处理器Q有的两者都有。这些电路板是用来使Y件正工作的。而工E的最后阶D则变成了对代码q行优化。最后一步的目标是得工作程序在一个廉Lgq_上运行?/p>

提高代码的效?br />所有现代的 C 和C++~译器都提供了一定程度上的代码优化。然而,大部分由~译器执行的优化技术仅涉及执行速度和代码大的一个^衡。你的程序能够变得更快或者更,但是不可能又变快又变。事实上Q在其中一个方面的提高׃对另一斚w产生负面的媄响。哪一斚w的提高对于程序更加的重要是由E序员来军_。知道这一点后Q无Z么时候遇到速度与大的矛盾Q编译器的优化阶D就会作出合适的选择?/p>

因ؓ你不可能让编译器Z同时做两U类型的优化Q我你让它尽其所能的减少E序的大。执行的速度通常只对于某些有旉限制或者是频繁执行的代码段是重要的。而且你可以通过手工的办法做很多事以提高q些代码D늚效率。然而,手工改变代码大小是一件很隄事情Q而且~译器处于一个更有利的位|,使得它可以在你所有的软g模块之间q行q种改变?/p>

直到你的E序工作hQ你可能已经知道或者是非常的清楚,哪一个子E序或者模块对于整体代码效率是最关键的。中断服务例E、高优先U的d、有实时限制的计、计密集型或者频J调用的函数都是候选对象。有一个叫作profiler 的工P它包括在一些Y件开发工L中,q个工具可以用来把你的视UK中到那些E序p大部分时?或者很多时?的例E上厅R?br />一旦你定了需要更高代码效率的例程Q可以运用下面的一U或者多U技术来减少它们的执行时间?/p>

inline 函数
?c++中,关键字inline 可以被加入到M函数的声明。这个关键字h~译器用函数内部的代码替换所有对于指出的函数的调用。这样做删去了和实际函数调用相关的时间开销Q这U做法在inline 函数频繁调用q且只包含几行代码的时候是最有效的?/p>

inline 函数提供了一个很好的例子Q它说明了有时执行的速度和代码的太小是如何反向关联的。重复的加入内联代码会增加你的程序的大小Q增加的大小和函数调用的ơ数成正比。而且Q很明显Q如果函数越大,E序大小增加得越明显。优化后的程序运行的更快了,但是现在需要更多的ROM?/p>

查询?br />switch 语句是一个普通的~程技术,使用旉要注意。每一个由tb机器语言实现的测试和跌{仅仅是ؓ了决定下一步要做什么工作,把宝贵的处理器旉耗尽了。ؓ了提高速度Q设法把具体的情冉|照它们发生的相对频率排序。换句话_把最可能发生的情冉|在第一Q最不可能的情况攑֜最后。这样会减少q_的执行时_但是在最差情况下Ҏ没有改善?/p>

如果每一个情况下都有许多的工作要做,那么也许把整个switch 语句用一个指向函数指针的表替换含更加有效。比如,下面的程序段是一个待改善的候选对象:

enum NodeType {NodeA, NodeB, NodeC}
switch(getNodeType())
{
case NodeA:
...
case NodeB:
...
case NodeC:
...
}
Z提高速度Q我们要用下面的代码替换q个switch 语句。这D代码的W一部分是准备工作:一个函数指针数l的创徏。第二部分是用更有效的一行语句替换switch 语句?/p>

int processNodeA(void);
int processNodeB(void);
int processNodeC(void);
/*
* Establishment of a table of pointers to functions.
*/
int (* nodeFunctions[])() = { processNodeA, processNodeB, processNodeC };
...
/*
* The entire switch statement is replaced by the next line.
*/
status = nodeFunctions[getNodeType()]();

手工~写汇编
一些Y件模块最好是用汇~语a来写。这使得E序员有Z把程序尽可能变得有效率。尽大部分的C/C++~译器生的机器代码比一个一般水q的E序员编写的机器代码要好的多Q但是对于一个给定的函数Q一个好的程序员仍然可能做得比一般水q的~译器要好。比如,在我职业生的早期,我用C 实现了一个数字o波器Q把它作为TI TMS320C30 数字信号处理器的输出目标。当时我们有?a style="color: #000000" >tb~译器也许是不知道,也许是不能利用一个特D的指oQ该指o准确地执行了我需要的那个数学操作。我用功能相同的内联汇编指o手工地替换了一DC 语言的@环,q样我就能够把整个计时间降低了十分之一以上?/p>

寄存器变?br />在声明局部变量的时候可以?register 关键字。这׃得编译器把变量放入一个多用选的寄存器,而不是堆栈里。合适地使用q种方珐Q它会ؓ~译器提供关于最l常讉K变量的提C,会稍微提高函数的执行速度。函数调用得是频繁Q这L改变p是可能提高代码的速度?/p>

全局变量
使用全局变量比向函数传递参数更加有效率。这样做去除了函数调用前参数入栈和函数完成后参数出栈的需要。实际上QQ何子E序最有效率的实现是根本没有参数。然而,军_使用全局变量对程序也可能有一些负作用。Y件工Eh士通常不鼓׃用全局变量Q努力促q模块化和重入目标,q些也是重要的考虑?/p>

轮询
中断服务例程l常用来提高E序的效率。然而,也有数例子׃q度和中断关联而造成实际上效率低下。在q些情况中,中断间的q_旉和中断的{待旉h相同量。这U情况下Q利用轮询与g讑֤通信可能会更好。当Ӟq也会软g的模块更?/p>

定点q算
除非你的目标q_包含一个Q点运的协处理器Q否则你会费很大的劲LU你E序中的点数据。编译器提供的Q点库包含了一l模仿Q点运协处理器指令组的子E序。很多这U函数要p比它们的整数q算函数更长的执行时_q且也可能是不可重入的?/p>

如果你只是利用QҎq行量的运,那么可能只利用定点运来实现它更好。虽然只是明白如何做到这一点就够困隄了,但是理论上用定点q算实现M点计算都是可能的?那就是所谓的点软g库?你最大的有利条g是,你可能不必只是ؓ了实C个或者两个计而实现整个IEEE 754 标准。如果真的需要那U类型的完整功能Q别d~译器的点库,d扑օ他加速你E序的方法吧?/p>


 



tbwshc 2013-07-23 17:19 发表评论
]]>
嵌入式的 C++标准http://www.shnenglu.com/tbwshc/archive/2013/07/23/202056.htmltbwshctbwshcTue, 23 Jul 2013 09:11:00 GMThttp://www.shnenglu.com/tbwshc/archive/2013/07/23/202056.htmlhttp://www.shnenglu.com/tbwshc/comments/202056.htmlhttp://www.shnenglu.com/tbwshc/archive/2013/07/23/202056.html#Feedback0http://www.shnenglu.com/tbwshc/comments/commentRss/202056.htmlhttp://www.shnenglu.com/tbwshc/services/trackbacks/202056.html作ؓ一个C++标准草案的合适子集,嵌入式C++省略了很多不限制下层语言可表达性的M可以省略的东ѝ这些被省略的特性不仅包括像多重l承性、虚拟基cR运行时cd识别和异常处理等昂贵的特性,而且q包括了一些最新的dҎ,比如Q模ѝ命?a style="color: #000000" >tbI问、新的类型{换等。所剩下的是一个C++的简单版本,它仍然是面向对象的ƈ且是C 的一个超集,但是它具有明显更的q行开销和更的q行库?br />很多商业的C++~译器已l专门地支持嵌入式C++标准。个别其他的~译器允许手工的用具体的语aҎ,q样׃你能够模仿嵌入式C++或者创Z的很个性化的C++语言?img src ="http://www.shnenglu.com/tbwshc/aggbug/202056.html" width = "1" height = "1" />

tbwshc 2013-07-23 17:11 发表评论
]]>
c++ 关于内存问题讨论http://www.shnenglu.com/tbwshc/archive/2013/07/10/201671.htmltbwshctbwshcWed, 10 Jul 2013 09:09:00 GMThttp://www.shnenglu.com/tbwshc/archive/2013/07/10/201671.htmlhttp://www.shnenglu.com/tbwshc/comments/201671.htmlhttp://www.shnenglu.com/tbwshc/archive/2013/07/10/201671.html#Feedback0http://www.shnenglu.com/tbwshc/comments/commentRss/201671.htmlhttp://www.shnenglu.com/tbwshc/services/trackbacks/201671.html最q在调试中遇到点内存寚w的问题,别h问我是怎么回事Q我赶紧偷偷查了一下,记录下来?/p>

不论是C、C++对于内存寚w的问题在原理上是一致的Q对齐的原因和表玎ͼ单ȝ一下,以便朋友们共享?/p>

一、内存对齐的原因
大部分的参考资料都是如是说的:
1、^台原?UL原因)Q不是所有的gq_都能讉KL地址上的L数据的;某些gq_只能在某些地址处取某些特定cd的数据,否则抛出g异常?br />2、性能原因Q数据结?其是栈)应该可能地在自然边界上寚w。原因在于,Z讉K未对齐的内存Q处理器需要作两次内存讉KQ而对齐的内存讉K仅需要一ơ访问?/p>

   也有的朋友说Q内存对齐出于对d的效率和数据的安全的考虑Q我觉得也有一定的道理?/p>

二、对齐规?br />    每个特定q_上的~译器都有自q默认“寚wpL”(也叫寚w模数)。比?2位windowsq_下,VC默认是按?bytes寚w?VC->Project->settings->c/c++->Code Generation中的truct member alignment 值默认是8)Q程序员可以通过预编译命?pragma pack(n)Qn=1,2,4,8,16来改变这一pLQ其中的n是你要指定?#8220;寚wpL”?/p>

    在嵌入式环境下,寚w往往与数据类型有养I特别是C~译器对~省的结构成员自然对届条件ؓ“N字节??#8221;QN卌成员数据cd的长度。如int型成员的自然对界条g?字节寚wQ而doublecd的结构成员的自然对界条g?字节寚w。若该成员的起始 偏移不位于该成员?#8220;默认自然对界条g”上,则在前一个节面后面添加适当个数的空字节。C~译器缺省的l构整体的自然对界条件ؓQ该l构所有成员中要求?最大自然对界条件。若l构体各成员长度之和不ؓ“l构整体自然对界条g的整数倍,则在最后一个成员后填充I字节?/p>

    那么可以得到如下的小l?

cd 寚w方式Q变量存攄起始地址相对于结构的起始地址的偏U量Q?br />Char    偏移量必Mؓsizeof(char)?的倍数
Short   偏移量必Mؓsizeof(short)?的倍数
int     偏移量必Mؓsizeof(int)?的倍数
float   偏移量必Mؓsizeof(float)?的倍数
double  偏移量必Mؓsizeof(double)?的倍数

   各成员变量在存放的时候根据在l构中出现的序依次甌I间Q同时按照上面的寚w方式调整位置Q空~的字节~译器会自动填充。同时ؓ了确保结构的大小为结 构的字节边界敎ͼ卌l构中占用最大空间的cd所占用的字节数Q的倍数Q所以在为最后一个成员变量申L间后Q还会根据需要自动填充空~的字节,也就?_l构体的dؓl构体最宽基本类型成员大的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。对于char数组Q字节宽度仍然认Zؓ1?/p>

   对于下述的一个结构体Q其寚w方式为:

struct Node1{

    double m1;
    char m2Q?br />    int m3;
};

  对于W一个变量m1Qsizeof(double)=8个字节;接下来ؓW二个成员m2分配I间Q这时下一个可以分配的地址对于l构的v始地址的偏U量?Q是sizeof(char)的倍数Q所以把m2存放在偏U量?的地Ҏ_齐方式,该成员变量占?sizeof(char)=1个字节;接下来ؓW三个成员m3分配I间Q这时下一个可以分配的地址对于l构的v始地址的偏U量?Q不是sizeof (int)=4的倍数Qؓ了满_齐方式对偏移量的U束问题Q自动填?个字节(q三个字节没有放什么东西)Q这时下一个可以分配的地址对于l构的v始地址的偏U量?2Q刚好是sizeof(int), ׃8+4+4 = 16恰好是结构体中最大空间类型double(8)的倍数Q所以sizeof(Node1) =16.

 

typedef struct{

    char a;

    int b;

    char c;

}Node2;

    成员a占一个字节,所以a攑֜了第1位的位置Q由于第二个变量b?个字节,Z证v始位|是4(sizeof(b))的倍数Q所以需要在a后面填充3?字节Q也是b攑֜了从W?位到W?位的位置Q然后就是c攑֜?的位|,此时4+4+1=9。接下来考虑字节边界敎ͼ9q不是最大空间类型int(4) 的倍数Q应该取大于9且是4的的最整?2Q所以sizeof(Node2) = 12.
typedef struct{

    char a;

    char b;

    int c;

}Node3;

   明显圎ͼsizeof(Node3) = 8

   对于l构体A中包含结构体B的情况,结构体A中的l构体成员B中的最宽的数据cd作ؓ该结构体成员B的数据宽度,同时l构体成员B必须满上述寚w的规定?/p>

   要注意在VC中有一个对齐系数的概念Q若讄了对齐系敎ͼ那么上述描述的对齐方式,则不适合?/p>

   例如Q?/p>

1字节寚w(#pragma pack(1))
输出l果Qsizeof(struct test_t) = 8 [两个~译器输Z致]
分析q程Q?br />成员数据寚w
#pragma pack(1)
struct test_t {
    int a;
    char b;
    short c;
    char d;
};
#pragma pack()
成员d?8Q?/p>

 

2字节寚w(#pragma pack(2))
输出l果Qsizeof(struct test_t) = 10 [两个~译器输Z致]
分析q程Q?br />成员数据寚w
#pragma pack(2)
struct test_t {
    int a;
    char b;
    short c;
    char d;
};
#pragma pack()
成员d?9Q?/p>

 

4字节寚w(#pragma pack(4))
输出l果Qsizeof(struct test_t) = 12 [两个~译器输Z致]
分析q程Q?br />1) 成员数据寚w
#pragma pack(4)
struct test_t { //按几寚wQ?偏移量ؓ后边W一个取模ؓ零的?br />int a;
char b;
short c;
char d;
};
#pragma pack()
成员d?9Q?/p>

 

8字节寚w(#pragma pack(8))
输出l果Qsizeof(struct test_t) = 12 [两个~译器输Z致]
分析q程Q?br />成员数据寚w
#pragma pack(8)
struct test_t {
int a;
char b;
short c;
char d;
};
#pragma pack()
成员d?9Q?/p>

 

16字节寚w(#pragma pack(16))
输出l果Qsizeof(struct test_t) = 12 [两个~译器输Z致]
分析q程Q?br />1) 成员数据寚w
#pragma pack(16)
struct test_t {
int a;
char b;
short c;
char d;
};
#pragma pack()
成员d?9Q?/p>

 

至于8字节寚w?6字节寚wQ我觉得q两个例子取得不好,没有太大的参考意义?/p>

(x666f)



tbwshc 2013-07-10 17:09 发表评论
]]>
如何C++接口的设计和声明http://www.shnenglu.com/tbwshc/archive/2013/06/25/201299.htmltbwshctbwshcTue, 25 Jun 2013 09:17:00 GMThttp://www.shnenglu.com/tbwshc/archive/2013/06/25/201299.htmlhttp://www.shnenglu.com/tbwshc/comments/201299.htmlhttp://www.shnenglu.com/tbwshc/archive/2013/06/25/201299.html#Feedback0http://www.shnenglu.com/tbwshc/comments/commentRss/201299.htmlhttp://www.shnenglu.com/tbwshc/services/trackbacks/201299.htmlM接口设计的一个准则:让接口容易被正确使用Q不Ҏ被误用?/p>

理想上:如何客户企图使用某个接口~没有获得他所预期的行为,q个代码不该通过~译Q如果代码通过了编译,他的行ؓp是客h惌的?/p>

1. 导入外覆cdQwrapper typesQ?/p>

2. 让typesҎ被正用,不容易被误用。尽量领你的types行ؓ与内|types一致?/p>

3. 设计class犹如设计type

新type的对象应该如何被创徏和销毁?Q自p计operatornewQoperatornew[],operator delete和operator delete[])

对象的初始化和对象的复制该有什么样的差?对应于不同的函数调用

新type的对象如果被passed by value Q意味着什?/p>

什么是新type?#8220;合法?#8221;Q(Q?Q?/p>

你的新type需要配合某个承图pdQ?/p>

你的心type需要什么样的{?/p>

什么样的操作符合函数对此新type而言是合理的

什么样的标准函数应该驳?/p>

谁该取用新type的成?/p>

什么是新type的未声明接口

你的新type有多么一般化

你真的需要一个新type?/p>

 

一、宁以pass-by-reference-to-const 替换 pass-by-value

1.tbw效率高,没有M构造函数或析构函数被调用,因ؓ没有M新对象被创徏?/p>

2. by refrenece方式传递参数还可以避免对象slicing 问题

二、必返回对象时Q别妄想q回其reference

所有用上static对象的设计,会造成多线E安全性的怀疑?/p>

三、将成员变量声明为privateQ?/strong>

1. 可以实现?#8220;不准讉K”?#8220;只读讉K”?#8220;d讉K”?#8220;惟写讉K”

2. 装Q它使我们能够改变事物而只影响有限客户?/p>

成员变量隐藏在函数接口的背后,可以?#8220;所有可能的实现”提供Ҏ。如Q?strong>tb变量被读或被写时通知其他对象、可以验证class的约束条件以及函数的前提和事后{帖;以及在多U程环境执行同步控制。。。。等?/p>

四、宁以non-member、non-friend替换member函数

  1. namespace WebBrowserStuff{ 
  2.         class WebBrowser{...}; 
  3.         void clearBrowser(WebBrowser& wb); 

五、若所有参数皆需要类型{换,请ؓ此采用non-member函数

  1. class Rational { 
  2. ... 
  3.  
  4. const Rational operator*(const Rational& lhs,const Rational& rhs) 
  5. return Rational( lhs.numerator()* rhs.numerator()
  6. ,lhs.denominator()*rhs.denominator() ); 
  7.  
  8. Rational oneFourthQ?Q?Q; 
  9. Rational resultQ?nbsp;
  10. result = oneFourth * 2; 
  11. result = 2*oneFourth; 

 六、考虑写出一个不抛异常的swap函数



tbwshc 2013-06-25 17:17 发表评论
]]>
Hello World!http://www.shnenglu.com/tbwshc/archive/2013/06/25/201298.htmltbwshctbwshcTue, 25 Jun 2013 09:12:00 GMThttp://www.shnenglu.com/tbwshc/archive/2013/06/25/201298.htmlhttp://www.shnenglu.com/tbwshc/comments/201298.htmlhttp://www.shnenglu.com/tbwshc/archive/2013/06/25/201298.html#Feedback0http://www.shnenglu.com/tbwshc/comments/commentRss/201298.htmlhttp://www.shnenglu.com/tbwshc/services/trackbacks/201298.html好像所有讲q编E的书都用同一个例子来开始,是在用L屏幕上显C出“HelloQWorld!”。L使用q个例子可能有一点叫人厌烦,可是它确实可以帮助读者迅速地接触到在~程环境中书写简单程序时的简便方法和可能的困难。就q个意义来说Q?#8220;HelloQWorld!”可以作ؓ验编E语a和计机q_的一个基准?/p>

不幸的是Q如果按照这个标准来_嵌入式系l可能是E序员工作中到的最隄计算机^C。甚臛_某些嵌入式系l中Q根本无法实?#8220;HelloQWorld!”E序。即使在那些可以实现q个E序的嵌入式pȝ里面Q文本字W串的输Z更像是目标的一部分而不是开始的一部分?/p>

你看Q?#8220;HelloQWorld!”CZ隐含的假设,是有一个可以打印字W串的输备。通常使用的是用户昄器上的一个窗口来完成q个功能。但是大多数的嵌入式pȝq没有一个显C器或者类似的输出讑֤。即使是寚w些有昄器的pȝQ通常也需要用一段嵌入式程序,通过调用昄驱动E序来实现这个功能。这对一个嵌入式~程者来说绝Ҏ一个相当具有挑战性的开端?/p>

看v来我们还是最好以一个小的,Ҏ实现q且高度可移植的联h式程序来开始,q样?strong>tbE序也不太会有编E错误。归根到底,我这本书l箋选用“HelloQWorld!”。这个例子的原因是,实现q个E序实在太简单了。这L在读者的E序W一ơ就q行不v来的时候,会去掉一个可能的原因Q即Q错误不是因Z码里的缺P相反Q问题出在开发工h者创建可执行E序的过E里面?/p>

嵌h式程序员在很大程度上必须要依靠自q力量来工作。在开始一个新目的时候,除了他所熟悉的编E语a的语法,他必首先假定什么东襉K没有q{hQ甚臌标准库都没有Q就是类似printf()和scanf()的那些程序员常常依赖的辅助函数。实际上Q库例程常常作ؓ~程语言的基本语法出现。可是这部分标准很难支持所有可能的计算q_Qƈ且常常被嵌入式系l编译器的制造商们所忽略?/p>

所以在q一章里你实际上找不到一个真正的”HelloQWorld!”E序Q相反,我们假定在第一个例子中只可以用最基本的C 语言语法。随着本书的进一步深人,我们会逐步向我们的指opȝ里添加C++的语法、标准库例程和一个等效的字符输出讑֤。然后,在第九章“l合所学的知识”里面。我们才最l实C?#8220;HelloQWorld!”E序。到那时候你顺利地C成ؓ一个嵌入式pȝ~程专家的道路?/p>

tbwshc 2013-06-25 17:12 发表评论
]]>
jizzjizzƷþ| AV12þ| þһ| þþþþþþƷŮ99| þþþþAVר| Ʒþþþþþ| þav뾫Ʒ˳| þ99ƷСѼ| Ⱦþۺ| þ97㽶| Ʒһþ| þþƷ| һaƬþëƬ| ŷƷþø| ҹƷþþþþëƬ| 99þ˾ƷۺϹۿ| þĻavŮ| þˬˬˬav| ھƷþþþav| ޾Ʒþò| ޹Ʒһþ| ݺɫþþһ| þ99Ʒþþþþ | þþƷһ| ɫþþۺ| þþƷƵ| AëƬþþþƷëƬ| þƵվ| ޹ƷþSM| þþƷһ| ԭۺϾþô˵| ھƷŷþþƷ| ޹Ʒþ66| Ʒþþþþ| AVþþþòվ| Ʒþþþþר| Ļþҹ| 97Ʒ97þþþþ| ɫav˾þô߽ӰԺ| þ޾ƷAVӣ| ɫۺϺϾþۿ|