EDN首页   博客首页 用户登陆  |  注册
aaa
发表于 2009/12/31 8:48:04

0

关于投票

lint使用简介

lint使用简介


LINT工具是一种软件质量保证工具,许多国外的大型专业软件公司,如微软公司,都把它作为程序检查工具,在程序合入正试版本或交付测试之前一定要保证通过了LINT检查,他们要求软件工程师在使用LINT时要打开所有的编译开关,如果一定要关闭某些开关,那么要给出关闭这些开关的正当理由。

  可想而知,如果从我们编码后第一次编译程序时就使用LINT来检查程序,并且保证消除所有的LINT告警,我们就不会遇到象今天这么多的告警信息。即使在今天,我们如果能抽出一定的精力来消除程序中的LINT告警,以后再维持这种无告警状态就是很容易的了。我们程序质量的提高也是不言而喻的。

  PC-LINT是GIMPEL?SOFTWARE公司的产品,其中的内容是非常广泛的,光是选项就有300多个,涉及到程序编译及语法使用中的方方面面。本篇培训材料旨在引导读者入门,学会PC-LINT的基本使用方法,起抛砖引玉的作用,能让读者从这里起步继续去研究如何娴熟地使用PC-LINT的各种选项,能让它充分为我们的开发工作服务。

1.概述
  如果要给LINT工具下一个形象点的定义,那就是:一种更加严格的编译器。它不仅可以象普通编译器那样检查出一般的语法错误,还可以检查出那些虽然完全合乎语法要求,但很可能是潜在的、不易发现的错误。请看下面的例子:
1:
2:char?*report(?int?m,?int?n,?char?*p?)
3:{
4:?int?result;
5:?char?*temp;
6:?long?nm;
7:?int?i,?k,?kk;
8:?char?name[11]?=?"Joe?Jakeson";
9:
10:?nm?=?n?*?m;
11:?temp?=?p?==?""???"null"?:?p;
12:?for(?i?=?0;?i?13:?{
14:?k++;
15:?kk?=?i;
16:?}
17:
18:?if(?k==?1?)?result?=?nm;
19:?else?if(?kk?>?0?)?result?=?1;
20:?else?if(?kk?<?0?)?result?=?-1;
21:
22:?if(?m?==?result?)?return(?temp?);
23:?else?return(?name?);
24:}
  上面的代码用一般的编译器编译是一段有效的代码,但是用PC-LINT编译就会有几个告警。首先第8行向name数组赋值时丢掉了nul字符,第10行的乘法精度会失准,第11行的比较有问题,第14行的变量k没有初始化,第15行的kk可能没有被初始化,第22行的result也有可能没有被初始化,第23行返回的是一个局部对象的地址。这段代码在大部分编译器下是可以顺利编译通过的,继续查找其中的错误就要靠人工调试程序,如果程序很大,这将是一项烦琐的工作,没有人可以保证能找出所有的这类问题,但PC-LINT只通过一次简单的编译就可做到,显然为我们节省了大量的开发时间。

  下面就让我们看看如何安装使用PC-LINT。
2.如何安装PC-LINT
  PC-LINT的软件的安装过程比较复杂,选项较多,下面根据安装过程,逐条说明每一步的含义。
0)如果是zip文件,将ZIP安装文件展开到目录C:\lint.ins下,进入COMMAND?PROMPT,先进行目录映射?subst?g:?c:\lint.ins,然后转到G:?,?执行install。其他步骤和下面的从软盘安装是一样的。

1)在A:驱插入PC-LINT安装盘,输入A:\>install命令,进入开始安装栏,按任意键继续,进入PC-LINT介绍栏,再按任意键继续。
2)进入环境选择栏,这一栏中有三个选项:
Windows?NT/Windows?95
MS-DOS(DOS?extended)
OS/2(32bit)
如果计算机安装了WIN95、WIN97、WIN98或WINNT要选择Windows?NT/Windows?95,如果
只有DOS则选择DOS。
3)进入安装目录选择栏,它推荐的是C:\>LINT,如不想安装在这个目录下,可输入自己想要安装的目录,然后按回车确认,如果要安装的目录不存在,它会提示为你建立这个目录。我们这里选C:\>LINT
4)选择安装盘所在的磁盘驱动器,我们这里选A:
5)判断是否要选择多种编译器或编译库的配置,如果要对不同编译环境下的程序进行L
INT,则选YES,否则选NO。然后回车确认。
6)这时看到一个编译器列表,在这个表中选择自己使用的编译器,如果表中没有自己使用的编译器,可选择通用编译器:Generic?Compilers。按回车确认。这个选项会体现在co-xxx.lnt文件中。
7)接着安装程序会让你选择一个的内存模型,可以根据自己程序区和数据区的实际大小选择一个恰当的内存模型。如果CPU为32位68K系列,则要选择:32-bit?Flat?Module。
内存模型的选项会体现在STD.LNT文件中。
8)选完内存模型后,会看到一个库类型的列表,在这里选择一个或多个编译时使用的库。这个选项会体现在LIB-xxx.LNT文件中。
9)接着是让你选择为使用C++编程提出过重要建议的作者,选择的某作者后,他提出的编程建议方面的选项将被打开。与作者选择有关的选项会体现在AU-xxx.LNT文件中。
10)下一步是设置包含文件目录。有两种选项,第一种是使用环境变量INCLUDE,环境变量在批处理文件中设置,环境变量后每个目录用分号隔开,例如可设成“INCLUDE=C:\MRI\MCC68K;D:\LAP\SRC\INC”。第二种选项是使用-i选项,-i选项体现在STD.LNT文件中,每个目录前以-I引导,目录间以空格分隔,例如可设成“-IC:\MRI\MCC68K?-ID:\LAP\SRC\INC”。如果选择使用-I选项,安装程序会接着让你输入包含文件所在的目录。
11)?如果前面选择了使用多个编译环境,这里将会问你是否选择更多的编译环境,如果选YES,将会从第6步开使重复。如果选NO则会结束编译器选择。
12)接下来将会准备产生一个?反映全局编译信息显示情况的选项文件OPTIONS.LNT,该文件的产生方式有两种,一种是安装程序对几个核心选项逐一解释并提问你是否取消该选项,如果你选择取消,则会体现在OPTIONS.LNT文件中,具体体现方式是在该类信息编码前加-e,后面第13~18步是逐一选择核心选项的过程。如果选择第二种选择方式,安装文件会先生成一个空的OPTIONS.LNT文件,等你以后在实际应用时加入必要的选项。
13)是否关闭赋值时的布尔测试告警,如:if(a=f()){...
14)是否关闭赋值时的有符号量和无符号量间的不匹配告警,通常情况下,这种赋值不会带来问题,选择关闭该告警信息的同时,其他类型的有符号量和无符号量间混合操作的告警仍然是打开的。
15)当把一个整形量赋值给一个比它短的量时,后者会丢失精度,例如把一个INT量赋值给给一个CHAR量。本步是让你选择是否关闭该类告警。
16)是否关闭左移带符号量的告警。通常PC-LINT会对所有带符号量的移动产生告警,但右移一般是由不同的CPU来确定是否将符号位移入,左移一般是不会产生什么问题的,所以可以选择关闭该告警。
17)在一个C函数被定义或声明前调用它,并不总是会产生错误,在这里可以选择是否关闭该告警选项。该选项对C++程序不起作用。
18)是否关闭“调用不存在的函数原型”告警。有些程序员不愿遵守严格的函数原形定义约定,但PC-LINT会在调用一个没有定义的函数原型时产生一个告警,在这里可以选择关闭该告警。
19)通过上面的步骤确定OPTIONS.LNT文件的形式后,接着是选择编译环境。PC-LINT提供了集成在多种开发环境中工作的功能,例如可集成在VC、BC、Source?Insight中。假如我们在这里选择Source?Insight。选择后安装程序会继续问你是否还选择其它的环境,可根据自己应用的实际情况选择一种或多种开发环境。开发环境的选择情况记录在env-xxx.lnt文件中。
20)安装程序会生成一个LIN.BAT文件,该文件是运行PC-LINT的批处理文件,为了使该文件能在任何路径下运行,安装程序提供了两种方法供你选择。第一种方法是让你选择把LIN.BAT拷贝到任何一个PATH目录下,在安装结束运行LCOPY.BAT文件时,会把LIN.BAT拷贝到你指定的目录。第二种方法是生成一个LSET.BAT文件,在每次使用PC-LINT前先运行它来设置路径,或者把LSET.BAT文件的内容拷贝到AUTOEXEC.BAT文件中。
21)在安装程序执行完后第一件事是在你安装的目录下执行LCOPY.BAT文件。它会从安装盘拷贝将一些文件拷贝到安装目录下,并根据你在安装过程中的选择来设置文件中的参数。
3.LINT?一个C文件
3.1用命令行方式进行LINT
如果使用LIN.BAT批处理文件进行LINT,在LINT前要先看一下该批处理文件中的内容,里面包含了LINT-NT命令和命令选项,可以根据自己的要求来修改、增减选项。我们看到,在这个批命令中嵌套了一个std.lnt文件,在std.lnt文件中还嵌套了co.lnt、options.lnt和lib-stl.lnt文件,原则上*.lnt文件是可以无限制嵌套,该类文件中一般都是了LINT的选项,可通过修改这些文件来修改LINT选项,选项是按照从左到右的顺序执行的。可执行下面命令行:
C:\abc\src>lin?alpha.c?beta.c?gamma.c
通常对于由多个C模块组成的程序,最好先分别对每个C模块单元进行LINT检查,做单元LINT时可如下运行:
C:\abs\src>lin?-u?alpha.c
其中-u是单元选项,使用-u后可以关闭一些检查多模块时会产生的告警,例如“函数未被使用”或“函数没有定义”等。
也可以不使用LIN.BAT批处理文件,而直接使用LINT命令。在DOS环境下LINT命令为LINT.EXE,在Windows95/NT环境下为LINT-NT.EXE,在OS2环境下为LINT-OS2.EXE。直接使用LINT命令要注意的一点是要在使用前预先设置LINT目录所在路径,最好的方法是把该路径加在AUTOEXEC.BAT文件中。其它的使用方法与使用批处理文件相同。例如:
C:\abs\src>lint-nt?-ic:\lint\?std.lnt?-os(_lint.tmp)?*.c
3.2用开发环境进行LINT
也可以使用开发环境来执行LINT操作,一般开发环境都支持运行可执行文件,但不一定支持运行批处理文件,下面用Source?Insight?,?Ultra?Edit,?MSVC?6.0?来举例说明如何在开发环境下进行LINT。
3.2.1?在Source?Insight中集成
如果你在安装过程中选定了使用某个开发环境,安装程序会在你安装的目录下生成一个env-xxx.lnt的文件,例如选择了Source?Insight就会有一个env-si.lnt文件。用编辑器打开该文件,在该文件开始的注释中说明了如何将PC-LINT功能集成在开发环境中,集成在Source?Insight中的过程如下:
1)从Options菜单中选择“Custom?Commands”命令项。
2)在Name栏中输入“PC-lint?”,原则上这个名称可以随便起,只要你能搞清楚它的含义就可以了。
3)在Run栏中输入“c:\lint\lint-nt?-u?-ic:\lint?std?env-si?%f”其中c:\lint是你PC-LINT的安装目录。
4)在Output栏中选择“Iconic?Window”、“Capture?Output”。
5)在Control栏中选择“Save?Files?First”。
6)在Source?Links?in?Output栏中选择“Parse?Links?in?Output”、“File,then?Line”。
7)在Pattern栏中输入“^\([^?]*\)?\([0-9]+\)”。
8)点Add键加入该命令。如下图:
9)使用时,在Source?Insight下打开要LINT的文件,打开Options菜单中的“Custom?Commands”命令项,在“Command”栏中选择“PC-lint?unit?check”命令运行即可。
注意到我的Run一栏的参数和上面的提示不一样,其实我的其他古怪参数都放到c:\lint\std.lnt中了。请注意,不论你怎样配置参数一定不要忘记了将si-env.lnt包含在你的配置文件里,否则就无法进行错误信息和程序的自动对应了。
为了使用方便,你还可以配置一下Menu按钮,将它加到系统菜0单里,这属于一般性的
Source?Insight应用,笔者就不在此赘述了。
第二笔者在NT中使用Source?Insight时,好象集成不了,原因暂时不明了。上面的例子在WIN?95下测试成功。
如果要修改LINT选项,可直接在Run栏中修改,也可专门编辑一个*.lnt文件放在c:\lint目录下,并将该文件名加入Run栏中,和命令行方式是一样的。
3.2.2在Ultra?Editor中集成
选取?Menu?|?Advanced?|?Tool?Configuration?...?,?显示如下图:
1)点按“Insert",
2)在command?line:中填写:c:\lint\lint-nt?c:\lint\std.lnt?%f
3)在Menu?Item中填写:PC-LINT
4)在Command?Output中选择:?(x)?Output?to?List?Box?和?(x)?Capture?Output
5)点按"OK"
如图所示的配置笔者在UE6.0?/?NT?4.0?下测试成功。
3.2.3?在MSVC?6.0中集成
基本原理是一样的:
1)选取?menu?|?tools?|?customize.....
2)选取?Tools?Tab:
3)点按主对话框上方的虚线小方框?New?a?tool?item
4)输入?name:?PC-LINT
5)输入?Command:?c:\lint\lint-nt.exe
6)输入?Arguments:?c:\lint\std.lnt?$(FilePath)
7)?选择?(x)?Use?Output?Window
8)Close
完成后,在tools菜单下就会有一项PC-LINT选项。
下面是笔者在VC6?/?Win?NT?4.0?的情况下的TOOL配置图:
3.3LINT选项
LINT选项可以放在注释中,例如:
/*lint?option1?option2?...?optional?commentary?*/
//lint?option1?option2?...?optional?commentary
选项间要以空格分开,lint命令一定要小写,并且紧跟在/*或//后面,不能有空格。如果选项由类似于操作符和操作数的部分组成,例如-esym(534,?printf,?scanf,?operat or?new),其中最后一个选项是operator?new,那么在operator和new中间只能有一个空
格。
选项还可以放在宏定义中,例如:
#define?DIVZERO(x)?/*lint?-save?-e54?*/?((x)?/o)?/*lint?-restore?*/
LINT的选项很多共有300多种,大体可分为以下几类:
1)错误信息禁止选项
该类选项是用于禁止生成某类错误信息的选项,最常用的是-e和+e,-e是禁止生成某类错误信息,+e是恢复生成某类错误信息。运行lint目录下的msg.exe可以得到msg.txt文件,这个长达5000行的文件包含了所有的错误信息号和解释。
-w?对于所有大于级别的告警信息都不显示。
-wlib()对于所有大于级别的关于库函数数的告警信息都不显示。我们可以用-wlib(0)来屏蔽所有的库函数的告警信息,-wlib(1)只显示库函数中的句法错误。
-esym(#,)?可以屏蔽对于特定符号的某告警信息。
2)变量类型大小选项
不同的目标机、编译系统变量类型的的大小(如短整形变量、整形变量等)会有所不同,该类选项用于为目标机设置变量类型的大小。由于默认的设置与大部分的编译器是匹配的,这些专门的设置通常情况下是不需要的,只在特别的目标机结构中才用。例如一个M68000目标机,它的int类型和指针类型通常是32bit的,这时你应该使用选项:-si4
-sp4。这些尺寸参数的当前值可以通过help屏来获得,例如可以输入以下命令行:
lin?-si4?-sp4??
3)冗长信息选项
冗长信息指的是LINT过程中产生的一些与编译过程有关的信息,而不是真正的告警信息、错误信息等。是否生成这些信息可以通过-v和+v选项来决定。+v是生成这些信息,-v是关闭这些信息,这组选项中除+v外,其它所有选项都可以关闭+v选项。
4)标记选项
以+f、++f、-f和--f开头的选项是标记选项。他们的逻辑含义分别如下:
+f...:通过把标志置为1而把它置为ON
-f...:通过把标志置为0而把它置为OFF
++f...:标志增1
--f...:标志减1
后面两个用于你想在局部把一个标志置为ON的情况,而不影响全局设置。例如你可以这样使用:
/*lint?++flb?*/
int?printf(?);
/*lint?--flb?*/
标记选项的种类很多,基本含义是用于打开或关闭某类语法情况使用,例如允许使用缩写结构体名称,允许使用无名联合体,把所有模块当作C++编译等。
5)消息显示选项
消息显示选项用于定义消息输出格式。主要有消息高度选项、消息宽度选项、消息格式选项等。
6)其它选项
其它选项中的种类很多,各种类间差异很大,在这里就不一一介绍了,建议大家看一看《PC-LINT》一书,第五章有对每种选项的详细说明。lint本身也有一些说明信息,?lint-nt?2>?lint.txt?然后狂按几个回车就可以生成一个lint选项的说明文件。
4.LINT一个工程下的多个C文件
4.1为何要LINT多个C文件
在程序编码初期,我们关心的可能只是单个C模块种中的语法问题,等到编程后期,对于由多个C模块组成的程序,我们希望了解当把多个模块连接在一起后是否还有存在于模块间的语法问题。这时编译器虽然能给出一些告警,但PC-LINT的连接能给出更多的告警。还有当我们能保证其中的几个模块相对稳定,而另外几个模块仍有问题时可以先将几个稳定的模块编译连接成一个目标文件,文件每次修改完成后先单独编译,然后连接入总的目标文件。
4.2如何LINT一个工程下的多个C文件
象我们平时使用的编译工具一样,PC-LINT在编译连接多个C文件时也会先把每个C文件编译生成中间的目标文件*.lob,然后再将所有的LOB文件连接在一起。LOB是Lint?Object?Module的缩写。这个文件中包含了一个C或C++模块的所有外部信息。生成LOB文件时有三种选项要注意:第一种是-u,如果要LINT生成LOB文件,就一定要加-u选项;第二种是-zero或-zero(500)选项,为了保证LOB文件在模块存在错误的情况下也能生成,就一定要加这个选项;第三种是-oo[(filename)],filename是生成的LOB文件的名称,在-oo后面,可加,也可不加,如不加,则LOB文件名与原C模块的名称相同,例如:
lint?-u?alpha.c?-oo(a1)
生成的LOB文件名为:a1.lob
lint?-u?alpha.c?-oo
生成的LOB文件名为:alpha.lob
LINT一个工程下的多个C模块,在用户的源程序目录下一般需要三个文件:?一个选项文件(*.lnt)、一个批处理文件(*.bat)和一个MAKEFILE文件(*.mak)。下面一一讲述如何制作这些文件。
1)选项文件(*.lnt)
选项文件在前面也提到过,你可以把你LINT每个C文件时时用到的所有公共选项罗列在该文件中,选项生效的顺序按照从左到右,从上到下的原则。该类文件可以层层嵌套,嵌套的层数没有限制。例如make.lnt文件:
-iC:\lint
std.lnt
+os(temp)
-e46
+vm
-zero
2)批处理文件(*.bat)
制作批处理文件时要注意要在该文件中调用TCMAKE.EXE文件和MAKEFILE文件,例如lintmake.mak文件:
@echo?Lint?Making?‘makelap‘:
tcmake?-flintmake.mak
@echo?End?of?making
3)MAKEFILE文件(*.mak)
MAKEFILE使用的TCMAKE的语法,和我们平时开发编译时使用的MAKEFILE文件语法格式一样,例如下面的lintmake.mak文件:
MCCPATH?=?c:\mcc68k
OPTION?=?-u?make.lnt?-oo
GLOBLE?=?os.h?l2lap.h
mail_depend?=?$(GLOBLE)?q931.h?mail.h
lapmain_depend?=?$(GLOBLE)?l1pubdef.h?q931.h?mail.h
lapos_depend?=?$(GLOBLE)
fhdlc1_depend?=?$(GLOBLE)?cpuhdlc.h?bd_prar.h?q931.h
OBJ?=?mail.lob?lapmain.lob?lapos.lob?fhdlc1.lob
project.lob?:?$(OBJ)
lint-nt?make.lnt?-e768?-e769?*.lob
mail.lob:?mail.c?$(mail_depend)
lint-nt?$(OPTION)?mail.c
lapmain.lob:?lapmain.c?$(lapmain_depend)
lint-nt?$(OPTION)?lapmain.c
lapos.lob:?lapos.c?$(lapos_depend)
lint-nt?$(OPTION)?lapos.c
fhdlc1.lob:?fhdlc1.c?$(fhdlc1_depend)
lint-nt?$(OPTION)?fhdlc1.c
4.3简单的LINT多个文件
假设我们的工程不复杂,我们可以负担起每次都将所有的文件都lint一遍的开销,也可以不使用上面的正规用法。笔者在实践中发现,将所有的*.c文件放在一个lint命令中,同样能完成lint整个工程的目的。
如:
lint-nt?c:\lint\std.lnt?AllMySource.lnt
在AllMySource.lnt中包括你的工程中的所有源文件:
a1.c
a2.c
a3.c
需要注意的是,在std.lnt文件中就不需要-u选项了。因为我们已经提供了所有的信息(

系统分类: 软件开发  |  用户分类: 编程类  |  标签: 无标签  |  来源: 转贴  | 

点击查看原文

发表评论 阅读全文(100) | 回复(0)

发表于 2008/12/16 15:13:29

1

关于投票

vc++6.0 "compiling... Error spawning cl.exe"

由于学习的需要,本来电脑中已经有了VISUAL STUDIO 2005的,可是上课的却用的是VISUAL C++6.0,虽然前者比后者更优秀,可是体积大,全英版的操作起来很不方便,于是就安了个VC,可问题也就来了,由于是已经安了VISUAL STUDIO 2005因此也就没它装在默认的路径中,可是在安了之后,试着运行了个程序,就出现了如标题所说的"Compiling... Error spawning cl.exe"的问题,(如上传的图片)(中文解释为,编译错误,错误产生在cl.exe)

一开始没注意细看, 以为是和STUDIO的冲突,所以就重新装在了不同的分区,可问题依旧,后来自己查了下,原来是VC找不到自己的编译器而引起的,于是就需要重新设置路径,到网上看了下,有如和我一样的问题的,也有人给出方法,可是大多没说清楚,甚至有误导的,在加上我先安的是VISUAL STUDIO,问题就更复杂了,所以看来还是要看自己找办法解决了.

有写人说了个大概,是"开始"->"程序"->"Microsoft Visual C++ 6.0"->"Microsoft Visual C++ 6.0 Tools"->"Options",而在tools中没这个选项,一些人就郁闷了,好不容易找到个有线索的办法,却因为自己的程序中没哪个选项而该不成,其实他们说的是对的,但是应该在打开VC后的菜单栏中的"Tools(工具)"中的"Options",找到多连选项卡的"Directories(路径)"中进行该才是,而且改的还挺多的,如下:(这是在默认的安装的前提下的)

该变四个文件的路径,即是"executable files","include files","library files","source files"(下面的也是借鉴的别人的)

executatble files:
C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin
C:\Program Files\Microsoft Visual Studio\VC98\BIN
C:\Program Files\Microsoft Visual Studio\Common\TOOLS
C:\Program Files\Microsoft Visual Studio\Common\TOOLS\WINNT

include files:
C:\Program Files\Microsoft Visual Studio\VC98\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\MFC\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\ATL\INCLUDE

library files:
C:\Program Files\Microsoft Visual Studio\VC98\LIB
C:\Program Files\Microsoft Visual Studio\VC98\MFC\LIB

source files:
C:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC
C:\Program Files\Microsoft Visual Studio\VC98\MFC\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\ATL\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC

其中我的是为目录:C:\Microsoft Visual C++ 6.0\...没有VC98这个次级文件夹,而是直接在C:\中的,后面的是一样的,其中我特意在MSDN的网的文章中看了,关于没有C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC 着个CRT的文件夹,它是个MS的连接库类文件,因为有不能加载的不足,所以就没随VC一起默认安装,但如有安装光盘,可以安的,但大概多数人都用的是网上的破解免注册的版本的吧^-^

所以呀,在网上找问题解决方法,要根据自己的实际情况来,最后我按最后的几个文件来依次该路径,最后就可以运行了,希望能给有同样装了不只一个IDE的朋友借鉴下!

系统分类: 软件开发  |  用户分类: 编程类  |  标签: vc++6.0 "compiling... Error spawning cl.exe  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(1698) | 回复(0)

发表于 2008/11/20 15:49:51

0

关于投票

activeskin 使用教程

ActiveSkin可以替你的软件作“换肤手术”,可以更换软件的外观,形状、颜色以及看起来的感觉。让软件界面不一定是长方形的,也可以是圆形、椭圆形或者不规则形状。不只是主窗口画面可以做变化,连软件的其他设定画面、对话框等等也都可以依照你的意思来设计,半透明、阴影等效果都可以。你还可以把软件设计得像是MAC、UNIX等其他操作系统的软件的样子。设计步骤有四个:1.先用绘图软件画出一张图,并且储存成bmp格式。2.用文本编辑软件编辑一个Skin.xml文件。3.用Visual Basic设计一个对话框,并且把ActiveSkin Control放进去。你必须把SkinPath指定到放Skin文件的位置。4.编辑ActiveSkin Control的OnSkinNotify。注意:安装后请先执行Install.bat,然后才能开始使用。

相关连接:
ActiveSkin 4.3 软件换肤在VC中的实现

      ActiveSkin作为一款优秀的Win32应用程序皮肤插件,有着使用简单,效果出色的诸多特点。正好这次在应用中用到了该插件,对使用中的注意事项做一个小结。

      首先要找到一个ActiveSkin的软件,并且正确安装,这个很简单,另外说一下的就是它带的一些Sample效果十分出色,可以看看。

⒈对话框应用
      在对话框中的应用不是很复杂,应该可以看到很多中文例程,这里大概说一下。
      Ⅰ在Stdafx.h中加入函数接口库。

   ##i nclude <atlbase.h>
   #import "actskn43.ocx" no_implementation raw_interfaces_only raw_native_types
   using namespace ACTIVESKINLib;


      Ⅱ在DlgApp.h文件里添加语句
   CComQIPtr<ISkin> m_pSkin;();


      Ⅲ在Dlg.cpp文件里添加语句
   ((YourApp*)AfxGetApp( ))->m_pSkin=GetDlgItem(IDC_SKIN)->GetControlUnknown();//m_pSkin是应用程序全局量。
   m_pSkin->LoadSkin(L"皮肤文件X的路径");//如果ActiveSkin控件中已有皮肤,此句可省略。
   m_pSkin->ApplySkin((int)m_hWnd);


      基本上就可以看到基本的效果了,如果还要更多,可以看看附带的文章或者是ActiveSkin附带的例子。

⒉框架应用。
      Ⅰ框架和对话框的应用有一些不同,应该是必须在对话框中将m_pSkin创建,然后框架才能够使用,于是必须增加一个对话框,并且在资源编辑器里面加入ActiveSkin的控件,同时可以在这里指定Skin的路径。
在app.h中加入对话框的头文件,并且将对话框的一个实例作为它的成员。然后在InitInstance()中加入以下代码:

if (!m_dlgSkin.Create(IDD_SKINDIALOG) //创建对话框并应用Skin|| !m_dlgSkin.m_hWnd || !m_pSkin)
{
MessageBox(NULL, "Could not initialize ActiveSkin control.\nPlease make sure it is installed properly.", "Error", MB_ICONEXCLAMATION);
return false;
}

      此句必须在AfxEnableControlContainer();之后。

      Ⅱ在对话框.cpp文件的OnInitDialog()里添加语句

((YourApp*)AfxGetApp())->m_pSkin = GetDlgItem(IDC_SKIN)->GetControlUnknown();


      对框架视图的切换,使用上还有一切问题,具体描述就是切换视图之后,视图上控件的皮肤会失去,需要修改一下代码,明天来做吧,今天太累了,玩几把《War3》再说,哈哈。

 

  ActiveSkin是一款给软件更换皮肤的ActiveX控件。它很还好的将软件界面设计工作从繁琐程序代码编写中解放出来,使得功能设计者可以专心于功能代码的实现,而把软件界面交给美工人员处理。提高了界面设计的工作效率,是一种很好的软件设计思想。

下面通过三个示例来介绍他的一般使用。

示例一:标准型皮肤SkinForm的对话框工程
  在VC环境下建立一个MFC基本对话框工程。在对话框的资源文件里Dlg.rc设计对话框界面中,删去已有的按钮Buttons和标签Lables,并插入ActiveSkin的ActiveX控件,命名为IDC_SKIN。右键点击ActiveSkin控件,在ActiveX属性里选择LoadSkin菜单项,可预先加载一个Skin文件。
在StdAfx.h中 //{{AFX_INSERT_LOCATION}} 之前添加以下语句:

    //目的是导入ActiveSkin的函数接口库。
    #i nclude <atlbase.h>
    #import "actskn43.ocx" no_implementation raw_interfaces_only raw_native_types
    using namespace ACTIVESKINLib;

接着,在Dlg.cpp文件里添加语句:

    CComQIPtr<ISkin> m_pSkin=GetDlgItem(IDC_SKIN)->GetControlUnknown();//m_pSkin是应用程序全局量。
    m_pSkin->LoadSkin(L"皮肤文件X的路径");//如果ActiveSkin控件中已有皮肤,此句可省略。
    m_pSkin->ApplySkin((int)m_hWnd);

  编译运行,可以看到皮肤文件X成为了程序的运行界面。如果想要在程序运行时更换皮肤,那也是可以的。在对话框上建立一个Button,并添加Click事件:

    void CMy1Dlg::OnBNewSkin() 
    {
      static char BASED_CODE szFilter[] = "ActiveSkin Files (*.skn)|*.skn||";//文件过滤器设置。
      CFileDialog dlg(FALSE, ".skn", NULL, OFN_HIDEREADONLY, szFilter);//Skin文件选择窗口。
      if (dlg.DoModal() == IDOK)//Skin文件选择成功:
      {
        USES_CONVERSION;
        m_pSkin->LoadSkin(T2W(dlg.GetPathName()));//载入指定的Skin文件。
        m_pSkin->ApplySkin((int)m_hWnd);//使当前Skin生效。
      }
    } 

  你会发现运行时主窗口已经换肤成功了,但“关于”对话框等非主窗口并没变化。需要在AboutDlg的OnInitDialog()事件中加入一句:

    m_pSkin->ApplySkin((int)m_hWnd);

再运行就一切Ok了!

示例二:标准皮肤SkinForm的多文档工程
  和示例一的做法类似,不同的只是子窗体在ChildFrm.cpp的Create事件中要做修改:

    BOOL bRes = CMDIChildWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, pContext);
    m_pSkin->ApplySkin((long)m_hWnd);
    return bRes;

这样就可以了。

示例三:自由皮肤SkinFreeForm的事件操作
  和上述的SkinForm不同,SkinFreeFrom是另一类型的皮肤文件方案。因此它的操作方法上就有所不同了。可以参照ActiveSkin自带样例中的DesktopColorizer一例。SkinForm和SkinFreeFrom的主要区别在于SkinApply方法和事件的驱动方式上。

    if(FAILED(m_pSkin->LoadSkin(Temp))||   //均使用LoadSkin()装载某一Skin,参数是Skin文件的路径名。
      FAILED(m_pSkin->ApplySkinByName((long)m_hWnd, L"FreeForm")))

      //SkinForm类型的皮肤使用ApplySkin使其生效,
      //这种方式会自动将某Skin中的所有SkinObject元素替代指定Handle的窗口。
      //SkinFreeForm类型的皮肤使用ApplySkinByName()使其生效,
      //其中第一个参数是窗口句柄,第二个参数是SkinBuilder中一个Object的名字。 
    {
      MessageBox("Could not load or apply the skin.");
      PostMessage(WM_CLOSE); 
      return FALSE;
    }

  事件驱动的区别:SkinForm换肤时不影响程序代码的原事件工作方式,只是界面上的换肤,因而SkinForm::ApplySkin(Handle)就OK了;但是SkinFreeForm就不同了,它必须用一个消息泵,采用消息的方式使程序获得Skin上的事件,而且在其事件中采用ISkinObject::GetName(BSTR *)获得相关的皮肤元素,用GetSkinnedWindow(hWnd).FindObject("Screen")来获取相应的元素句柄设置元素状态。简单的消息泵可以通过Skin控件上右键Event设置并编写。
  具体实现请看示例源代码。示例在使用前请安装好ActiveSkin4.3,可能还需要修改事例中Skin控件初始的LoadSkin(Skin文件)才能正常使用。

系统分类: 软件开发  |  用户分类: 编程类  |  标签: 无标签  |  来源: 转贴  | 

点击查看原文

发表评论 阅读全文(2516) | 回复(0)

发表于 2008/11/14 11:28:18

1

关于投票

MSP430 如何在c语言中定位程序地址

(1)汇编用RSEG XXXXH定位.用C定位程序时要修改*.xcl文件,具体做法是:
1.打开相应的*c.xcl文件,用"-Z(CODE)段名=程序定位的目标段-FFDF"定义段的起始地址.
2.在自己的C程序中用#pragma codeseg(段名)定位自己的程序
3.结束后恢复编译器的默认定位#pragma default
这样就可以了.
 
#include <msp430x11x1.h>
void asd(void);
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= 0x01; // Set P1.0 to output direction

for (;;)
{
unsigned int i;

P1OUT ^= 0x01; // Toggle P1.0 using exclusive-OR

i = 50000; // Delay
do (i--);
while (i != 0);
}
}
#pragma codeseg(AAA)
void asd(void)
{_NOP();
}


xcl:
-Z(CODE)CODE,CONST,CSTR,CDATA0,CCSTR=F100-FFDF
-Z(CODE)AAA=F000-F0EE

进入c-cpy看memory

系统分类: 软件开发  |  用户分类: 编程类  |  标签: msp430 定位  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(1229) | 回复(2)

发表于 2008/10/23 22:32:55

0

关于投票

如何在8051上搭建自己的web server

http://space.ednchina.com/upload/2008/10/23/d8db8be2-f381-493e-8c0b-fc881c4e2f41.rar

系统分类: 通信网络  |  用户分类: 编程类  |  标签: 无标签  |  来源: 整理  | 

点击查看原文

发表评论 阅读全文(503) | 回复(0)

发表于 2008/10/21 17:27:17

4

关于投票

基于ZigBee的CC2430 CC2431协议栈源代码

http://space.ednchina.com/upload/2008/10/23/bd38b83f-ac7c-46c7-afda-e9a56440e400.rarhttp://space.ednchina.com/upload/2008/10/23/d04039a8-55d2-438a-9e1f-ba3e66435c50.rarhttp://space.ednchina.com/upload/2008/10/23/12c0048c-87e7-4b36-b744-dcbe5f57e55c.rarIAR基于ZigBee的CC2430_CC2431协议栈源代码

系统分类: RFID  |  用户分类: 编程类  |  标签: IAR CC2430 CC2431 ZigBee  |  来源: 整理  | 

点击查看原文

发表评论 阅读全文(3159) | 回复(26)

发表于 2008/9/26 10:02:50

2

关于投票

C语言面试题总汇

C语言面试题总汇

4.    static有什么用途?(请至少说明两种)
1.限制变量的作用域
2.设置变量的存储域
7.    引用与指针有什么区别?
1) 引用必须被初始化,指针不必。
2) 引用初始化以后不能被改变,指针可以改变所指的对象。

 

 

 


2) 不存在指向空值的引用,但是存在指向空值的指针。

8.    描述实时系统的基本特性
在特定时间内完成特定的任务,实时性与可靠性
9.    全局变量和局部变量在内存中是否有区别?如果有,是什么区别?
全局变量储存在静态数据库,局部变量在堆栈
10.   什么是平衡二叉树?
左右子树都是平衡二叉树 且左右子树的深度差值的绝对值不大于1
11.   堆栈溢出一般是由什么原因导致的?
没有回收垃圾资源
12.   什么函数不能声明为虚函数?
constructor
13.   冒泡排序算法的时间复杂度是什么?
O(n^2)
14.   写出float x 与“零值”比较的if语句。
if(x>0.000001&&x<-0.000001)
16.   Internet采用哪种网络协议?该协议的主要层次结构?
tcp/ip 应用层/传输层/网络层/数据链路层/物理层
17.   Internet物理地址和IP地址转换采用什么协议?
ARP (Address Resolution Protocol)(地址解析协议)
18.IP地址的编码分为哪俩部分?
IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位。


2.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。
循环链表,用取余操作做
3.不能做switch()的参数类型是:
switch的参数不能为实型。

华为
1、局部变量能否和全局变量重名?
答:能,局部会屏蔽全局。要用全局变量,需要使用"::"
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内
2、如何引用一个已经定义过的全局变量?
答:extern
可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错
3、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
答:可以,在不同的C文件中以static形式来声明同名全局变量。
可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错
4、语句for( ;1 ;)有什么问题?它是什么意思?
答:和while(1)相同。
5、do……while和while……do有什么区别?
答:前一个循环一遍再判断,后一个判断以后再循环
6、请写出下列代码的输出内容
#i nclude<stdio.h>
main()
{
int a,b,c,d;
a=10;
b=a++;
c=++a;
d=10*a++;
printf("b,c,d:%d,%d,%d",b,c,d);
return 0;
}
答:10,12,120

1、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。
从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。
static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件

static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
2、程序的局部变量存在于(堆栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中。
3、设有以下说明和定义:
typedef union {long i; int k[5]; char c;} DATE;
struct data { int cat; DATE cow; double dog;} too;
DATE max;
则语句 printf("%d",sizeof(struct date)+sizeof(max));的执行结果是:___52____
答:DATE是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20
data是一个struct, 每个变量分开占用空间. 依次为int4 + DATE20 + double8 = 32.
所以结果是 20 + 32 = 52.
当然...在某些16位编辑器下, int可能是2字节,那么结果是 int2 + DATE10 + double8 = 20
4、队列和栈有什么区别?
队列先进先出,栈后进先出
5、写出下列代码的输出内容
#i nclude<stdio.h>
int inc(int a)
{
return(++a);
}
int multi(int*a,int*b,int*c)
{
return(*c=*a**b);
}
typedef int(FUNC1)(int in);
typedef int(FUNC2) (int*,int*,int*);

void show(FUNC2 fun,int arg1, int*arg2)
{
INCp=&inc;
int temp =p(arg1);
fun(&temp,&arg1, arg2);
printf("%d\n",*arg2);
}

main()
{
int a;
show(multi,10,&a);
return 0;
}
答:110
7、请找出下面代码中的所以错误
说明:以下代码是把一个字符串倒序,如“abcd”倒序后变为“dcba”

1、#i nclude"string.h"
2、main()
3、{
4、 char*src="hello,world";
5、 char* dest="NULL";
6、 int len="strlen"(src);
7、 dest=(char*)malloc(len);
8、 char* d="dest";
9、 char* s="src"[len];
10、 while(len--!=0)
11、 d++=s--;
12、 printf("%s",dest);
13、 return 0;
14、}
答:
方法1:
int main(){
char* src = "hello,world";
int len = strlen(src);
char* dest = (char*)malloc(len+1);//要为\0分配一个空间
char* d = dest;
char* s = &src[len-1];//指向最后一个字符
while( len-- != 0 )
*d++=*s--;
*d = 0;//尾部要加\0
printf("%s\n",dest);
free(dest);// 使用完,应当释放空间,以免造成内存汇泄露
return 0;
}
方法2:
#i nclude <stdio.h>
#i nclude <string.h>
main()
{
char str[]="hello,world";
int len="strlen"(str);
char t;
for(int i="0"; i<len/2; i++)
{
t=str[i];
str[i]=str[len-i-1]; str[len-i-1]=t;
}
printf("%s",str);
return 0;
}
1.-1,2,7,28,,126请问28和126中间那个数是什么?为什么?
第一题的答案应该是4^3-1=63
规律是n^3-1(当n为偶数0,2,4)
      n^3+1(当n为奇数1,3,5)
答案:63
2.用两个栈实现一个队列的功能?要求给出算法和思路!
设2个栈为A,B, 一开始均为空.

入队:
将新元素push入栈A;

出队:
(1)判断栈B是否为空;
(2)如果不为空,则将栈A中所有元素依次pop出并push到栈B;
(3)将栈B的栈顶元素pop出;

这样实现的队列入队和出队的平摊复杂度都还是O(1), 比上面的几种方法要好。3.在c语言库函数中将一个字符转换成整型的函数是atool()吗,这个函数的原型是什么?
函数名: atol
功 能: 把字符串转换成长整型数
用 法: long atol(const char *nptr);
程序例:
#i nclude <stdlib.h>
#i nclude <stdio.h>
int main(void)
{
long l;
char *str = "98765432";

l = atol(lstr);
printf("string = %s integer = %ld\n", str, l);
return(0);
}
2.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
c用宏定义,c++用inline
  3.直接链接两个信令点的一组链路称作什么?
PPP点到点连接
  4.接入网用的是什么接口?
  5.voip都用了那些协议?
  6.软件测试都有那些种类?
黑盒:针对系统功能的测试    白合:测试函数功能,各函数接口
  7.确定模块的功能和模块的接口是在软件设计的那个队段完成的?
概要设计阶段
  8.enum string
    {
    x1,
    x2,
    x3=10,
    x4,
    x5,
    }x;
   问x= 0x801005,0x8010f4  ;
  9.unsigned char *p1;
    unsigned long *p2;
    p1=(unsigned char *)0x801000;
    p2=(unsigned long *)0x810000;
    请问p1+5=  ;
        p2+5=  ;
三.选择题:
  1.Ethternet链接到Internet用到以下那个协议?
  A.HDLC;B.ARP;C.UDP;D.TCP;E.ID
  2.属于网络层协议的是:
  A.TCP;B.IP;C.ICMP;D.X.25
  3.Windows消息调度机制是:
  A.指令队列;B.指令堆栈;C.消息队列;D.消息堆栈;
  4.unsigned short hash(unsigned short key)
    {
      return (key>>)%256
    }
   请问hash(16),hash(256)的值分别是:
  A.1.16;B.8.32;C.4.16;D.1.32
四.找错题:
  1.请问下面程序有什么错误?
   int a[60][250][1000],i,j,k;
   for(k=0;k<=1000;k++)
    for(j=0;j<250;j++)
     for(i=0;i<60;i++)
      a[i][j][k]=0;
把循环语句内外换一下
  2.#define Max_CB 500
    void LmiQueryCSmd(Struct MSgCB * pmsg)
     {
     unsigned char ucCmdNum;
     ......
   
     for(ucCmdNum=0;ucCmdNum<Max_CB;ucCmdNum++)
      {
      ......;
      }
死循环
   3.以下是求一个数的平方的程序,请找出错误:
    #define SQUARE(a)((a)*(a))
    int a="5";
    int b;
    b="SQUARE"(a++);
   4.typedef unsigned char BYTE
     int examply_fun(BYTE gt_len; BYTE *gt_code)
      { 
      BYTE *gt_buf;
      gt_buf=(BYTE *)MALLOC(Max_GT_Length);
      ......
      if(gt_len>Max_GT_Length)
        {
        return GT_Length_ERROR; 
        }
        .......
      }
五.问答题:
   1.IP Phone的原理是什么?
IPV6
   2.TCP/IP通信建立的过程怎样,端口有什么作用?
三次握手,确定是哪个应用程序使用该协议
   3.1号信令和7号信令有什么区别,我国某前广泛使用的是那一种?
   4.列举5种以上的电话新业务?

微软亚洲技术中心的面试题!!!
1.进程和线程的差别。
线程是指进程内的一个执行单元,也是进程内的可调度实体.
与进程的区别:
(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行
(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源.
(4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
2.测试方法
人工测试:个人复查、抽查和会审
机器测试:黑盒测试和白盒测试

2.Heap与stack的差别。
Heap是堆,stack是栈。
Stack的空间由操作系统自动分配/释放,Heap上的空间手动分配/释放。
Stack空间有限,Heap是很大的自由存储区
C中的malloc函数分配的内存空间即在堆上,C++中对应的是new操作符。
程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上进行
3.Windows下的内存是如何管理的?
4.介绍.Net和.Net的安全性。
5.客户端如何访问.Net组件实现Web Service?
6.C/C++编译器中虚表是如何完成的?
7.谈谈COM的线程模型。然后讨论进程内/外组件的差别。
8.谈谈IA32下的分页机制
小页(4K)两级分页模式,大页(4M)一级
9.给两个变量,如何找出一个带环单链表中是什么地方出现环的?
一个递增一,一个递增二,他们指向同一个接点时就是环出现的地方
10.在IA32中一共有多少种办法从用户态跳到内核态?
通过调用门,从ring3到ring0,中断从ring3到ring0,进入vm86等等
11.如果只想让程序有一个实例运行,不能运行两个。像winamp一样,只能开一个窗口,怎样实现?
用内存映射或全局原子(互斥变量)、查找窗口句柄..
FindWindow,互斥,写标志到文件或注册表,共享内存。.  
12.如何截取键盘的响应,让所有的‘a’变成‘b’?
键盘钩子SetWindowsHookEx
 13.Apartment在COM中有什么用?为什么要引入?
 14.存储过程是什么?有什么用?有什么优点?
我的理解就是一堆sql的集合,可以建立非常复杂的查询,编译运行,所以运行一次后,以后再运行速度比单独执行SQL快很多
 15.Template有什么特点?什么时候用?
16.谈谈Windows DNA结构的特点和优点。


网络编程中设计并发服务器,使用多进程 与 多线程 ,请问有什么区别?
1,进程:子进程是父进程的复制品。子进程获得父进程数据空间、堆和栈的复制品。
2,线程:相对与进程而言,线程是一个更加接近与执行体的概念,它可以与同进程的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
两者都可以提高程序的并发度,提高程序运行效率和响应时间。
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。

思科
1. 用宏定义写出swap(x,y)
#define swap(x, y)\
x = x + y;\
y = x - y;\
x = x - y;
2.数组a[N],存放了1至N-1个数,其中某个数重复一次。写一个函数,找出被重复的数字.时间复杂度必须为o(N)函数原型:
int do_dup(int a[],int N)
3 一语句实现x是否为2的若干次幂的判断
int i = 512;
cout << boolalpha << ((i & (i - 1)) ? false : true) << endl;
4.unsigned int intvert(unsigned int x,int p,int n)实现对x的进行转换,p为起始转化位,n为需要转换的长度,假设起始点在右边.如x=0b0001 0001,p=4,n=3转换后x=0b0110 0001
unsigned int intvert(unsigned int x,int p,int n){
unsigned int _t = 0;
unsigned int _a = 1;
for(int i = 0; i < n; ++i){
_t |= _a;
_a = _a << 1;
}
_t = _t << p;
x ^= _t;
return x;
}

慧通:
什么是预编译
何时需要预编译:
1、总是使用不经常改动的大型代码体。
2、程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头。
char * const p;
char const * p
const char *p

上述三个有什么区别?
char * const p; //常量指针,p的值不可以修改
char const * p;//指向常量的指针,指向的常量值不可以改
const char *p; //和char const *p

char str1[] = "abc";
char str2[] = "abc";

const char str3[] = "abc";
const char str4[] = "abc";

const char *str5 = "abc";
const char *str6 = "abc";

char *str7 = "abc";
char *str8 = "abc";


cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;

结果是:0 0 1 1
解答:str1,str2,str3,str4是数组变量,它们有各自的内存空间;
而str5,str6,str7,str8是指针,它们指向相同的常量区域。


12. 以下代码中的两个sizeof用法有问题吗?[C易]
void UpperCase( char str[] ) // 将 str 中的小写字母转换成大写字母
{
    for( size_t i="0"; i<sizeof(str)/sizeof(str[0]); ++i )
        if( 'a'<=str[i] && str[i]<='z' )
            str[i] -= ('a'-'A' );
}
char str[] = "aBcDe";
cout << "str字符长度为: " << sizeof(str)/sizeof(str[0]) << endl;
UpperCase( str );
cout << str << endl;

答:函数内的sizeof有问题。根据语法,sizeof如用于数组,只能测出静态数组的大小,无法检测动态分配的或外部数组大小。函数外的str是一个静态定义的数组,因此其大小为6,函数内的str实际只是一个指向字符串的指针,没有任何额外的与数组相关的信息,因此sizeof作用于上只将其当指针看,一个指针为4个字节,因此返回4。

一个32位的机器,该机器的指针是多少位
指针是多少位只要看地址总线的位数就行了。80386以后的机子都是32的数据总线。所以指针的位数就是4个字节了。

main()
{
  int a[5]={1,2,3,4,5};
   int *ptr=(int *)(&a+1);

   printf("%d,%d",*(a+1),*(ptr-1));
}
输出:2,5
*(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5
&a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)
int *ptr=(int *)(&a+1);
则ptr实际是&(a[5]),也就是a+5
原因如下:
&a是数组指针,其类型为 int (*)[5];
而指针加1要根据指针类型加上一定的值,
不同类型的指针+1之后增加的大小不同
a是长度为5的int数组指针,所以要加 5*sizeof(int)
所以ptr实际是a[5]
但是prt与(&a+1)类型是不一样的(这点很重要)
所以prt-1只会减去sizeof(int*)
a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5].


1.请问以下代码有什么问题:
int  main()
{
char a;
char *str=&a;
strcpy(str,"hello");
printf(str);
return 0;
}
没有为str分配内存空间,将会发生异常
问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。

char* s="AAA";
printf("%s",s);
s[0]='B';
printf("%s",s);
有什么错?
"AAA"是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。
cosnt char* s="AAA";
然后又因为是常量,所以对是s[0]的赋值操作是不合法的。

1、写一个“标准”宏,这个宏输入两个参数并返回较小的一个。
.#define Min(X, Y) ((X)>(Y)?(Y):(X))//结尾没有;
2、嵌入式系统中经常要用到无限循环,你怎么用C编写死循环。
while(1){}或者for(;;)
3、关键字static的作用是什么?
定义静态变量
4、关键字const有什么含意?
表示常量不可以修改的变量。
5、关键字volatile有什么含意?并举出三个不同的例子?
提示编译器对象的值可能在编译器未监测到的情况下改变。


int (*s[10])(int) 表示的是什么啊
int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param)的函数。


1.有以下表达式:
int a="248"; b="4";int const c="21";const int *d=&a;
int *const e=&b;int const *f const =&a;
请问下列表达式哪些会被编译器禁止?为什么?
*c=32;d=&b;*d=43;e=34;e=&a;f=0x321f;
*c 这是个什么东东,禁止
*d 说了是const, 禁止
e = &a 说了是const 禁止
const *f const =&a; 禁止
2.交换两个变量的值,不使用第三个变量。即a=3,b=5,交换之后a=5,b=3;
有两种解法, 一种用算术算法, 一种用^(异或)
a = a + b;
b = a - b;
a = a - b;
or
a = a^b;// 只能对int,char..
b = a^b;
a = a^b;
or
a ^= b ^= a;
3.c和c++中的struct有什么不同?
c和c++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。c++中struct和class的主要区别在于默认的存取权限不同,struct默认为public,而class默认为private
4.#i nclude <stdio.h>
  #i nclude <stdlib.h>
  void getmemory(char *p)
  {
    p=(char *) malloc(100);
    strcpy(p,"hello world");
  }
  int main( )
  {
    char *str=NULL;
    getmemory(str);
    printf("%s/n",str);
    free(str);
    return 0;
   }
程序崩溃,getmemory中的malloc 不能返回动态内存, free()对str操作很危险
5.char szstr[10];
  strcpy(szstr,"0123456789");
  产生什么结果?为什么?
  长度不一样,会造成非法的OS
6.列举几种进程的同步机制,并比较其优缺点。
   原子操作
信号量机制
   自旋锁
   管程,会合,分布式系统

7.进程之间通信的途径
共享存储系统
消息传递系统
管道:以文件系统为基础
11.进程死锁的原因
资源竞争及进程推进顺序非法
12.死锁的4个必要条件
互斥、请求保持、不可剥夺、环路
13.死锁的处理
鸵鸟策略、预防策略、避免策略、检测与解除死锁
15.   操作系统中进程调度策略有哪几种?
FCFS(先来先服务),优先级,时间片轮转,多级反馈
8.类的静态成员和非静态成员有何区别?
类的静态成员每个类只有一个,非静态成员每个对象一个
9.纯虚函数如何定义?使用时应注意什么?
virtual void f()=0;
是接口,子类必须要实现
10.数组和链表的区别
数组:数据顺序存储,固定大小
连表:数据可以随机存储,大小可动态改变

12.ISO的七层模型是什么?tcp/udp是属于哪一层?tcp/udp有何优缺点?
应用层
表示层
会话层
运输层
网络层
物理链路层
物理层
tcp /udp属于运输层
TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。
与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较简单, UDP 头包含很少的字节,比 TCP 负载消耗少。
tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好
udp: 不提供稳定的服务,包头小,开销小  


1:(void *)ptr 和 (*(void**))ptr的结果是否相同?其中ptr为同一个指针
.(void *)ptr 和 (*(void**))ptr值是相同的
2:int main()
   {
    int x="3";
    printf("%d",x);
    return 1;
  
   }
问函数既然不会被其它函数调用,为什么要返回1?
mian中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息


1,要对绝对地址0x100000赋值,我们可以用
(unsigned int*)0x100000 = 1234;
那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?
*((void (*)( ))0x100000 ) ( );
首先要将0x100000强制转换成函数指针,即:
(void (*)())0x100000
然后再调用它:
*((void (*)())0x100000)();
用typedef可以看得更直观些:
typedef void(*)() voidFuncPtr;
*((voidFuncPtr)0x100000)();
2,已知一个数组table,用一个宏定义,求出数据的元素个数
#define NTBL
#define NTBL (sizeof(table)/sizeof(table[0]))

面试题: 线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈?
进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。

每个线程有自己的堆栈。
DLL中有没有独立的堆栈,这个问题不好回答,或者说这个问题本身是否有问题。因为DLL中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL中的代码是EXE中的线程所调用,那么这个时候是不是说这个DLL没有自己独立的堆栈?如果DLL中的代码是由DLL自己创建的线程所执行,那么是不是说DLL有独立的堆栈?

以上讲的是堆栈,如果对于堆来说,每个DLL有自己的堆,所以如果是从DLL中动态分配的内存,最好是从DLL中删除,如果你从DLL中分配内存,然后在EXE中,或者另外一个DLL中删除,很有可能导致程序崩溃


unsigned short A = 10;
printf("~A = %u\n", ~A);

char c="128";
printf("c=%d\n",c);

输出多少?并分析过程
第一题,~A =0xfffffff5,int值 为-11,但输出的是uint。所以输出4294967285
第二题,c=0x10,输出的是int,最高位为1,是负数,所以它的值就是0x00的补码就是128,所以输出-128。
这两道题都是在考察二进制向int或uint转换时的最高位处理。

分析下面的程序:
void GetMemory(char **p,int num)
{
    *p=(char *)malloc(num);
   
}       
int main()
{
    char *str=NULL;
   
    GetMemory(&str,100);
   
    strcpy(str,"hello");
   
    free(str);
   
    if(str!=NULL)
    {
        strcpy(str,"world");
    }   
       
    printf("\n str is %s",str);
    getchar();
}   
问输出结果是什么?希望大家能说说原因,先谢谢了
输出str is world。
free 只是释放的str指向的内存空间,它本身的值还是存在的.
所以free之后,有一个好的习惯就是将str=NULL.
此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的,
尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world来。
这是因为,进程中的内存管理一般不是由操作系统完成的,而是由库函数自己完成的。
当你malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的,只不过。。。。。。。。楼上都说过了,最好别这么干。

char a[10],strlen(a)为什么等于15?运行的结果

#i nclude "stdio.h"
#i nclude "string.h"

void main()
{

char aa[10];
printf("%d",strlen(aa));
}

sizeof()和初不初始化,没有关系;
strlen()和初始化有关。


char (*str)[20];/*str是一个数组指针,即指向数组的指针.*/
char *str[20];/*str是一个指针数组,其元素为指针型数据.*/

long a="0x801010";
a+5=?
0x801010用二进制表示为:“1000 0000 0001 0000 0001 0000”,十进制的值为8392720,再加上5就是8392725罗
1)给定结构struct A
{
       char t:4;
       char k:4;
       unsigned short i:8;
       unsigned long m;
};问sizeof(A) = ?
给定结构struct A
{
       char t:4; 4位
       char k:4; 4位
       unsigned short i:8; 8位     
       unsigned long m; // 偏移2字节保证4字节对齐
}; // 共8字节
2)下面的函数实现在一个数上加一个数,有什么错误?请改正。
int add_n ( int n )
{
    static int i = 100;
    i += n;
    return i;
}
当你第二次调用时得不到正确的结果,难道你写个函数就是为了调用一次?问题就出在 static上?


// 帮忙分析一下
#i nclude<iostream.h>
#i nclude <string.h>
#i nclude <malloc.h>
#i nclude <stdio.h>
#i nclude <stdlib.h>
#i nclude <memory.h>
typedef struct  AA
{
        int b1:5;
        int b2:2;
}AA;
void main()
{
        AA aa;
        char cc[100];
         strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");
       memcpy(&aa,cc,sizeof(AA));
        cout << aa.b1 <<endl;
        cout << aa.b2 <<endl;
}
答案是 -16和1
首先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit.
经过strcpy和memcpy后,aa的4个字节所存放的值是:
0,1,2,3的ASC码,即00110000,00110001,00110010,00110011
所以,最后一步:显示的是这4个字节的前5位,和之后的2位
分别为:10000,和01
因为int是有正负之分  所以:答案是-16和1

求函数返回值,输入x=9999;
int func ( x )
{
    int countx = 0;
    while ( x )
    {
        countx ++;
        x = x&(x-1);
    }
    return countx;
}
结果呢?
知道了这是统计9999的二进制数值中有多少个1的函数,且有
9999=9×1024+512+256+15

9×1024中含有1的个数为2;
512中含有1的个数为1;
256中含有1的个数为1;
15中含有1的个数为4;
故共有1的个数为8,结果为8。
1000 - 1 = 0111,正好是原数取反。这就是原理。
用这种方法来求1的个数是很效率很高的。
不必去一个一个地移位。循环次数最少。

int a,b,c 请写函数实现C=a+b ,不可以改变数据类型,如将c改为long int,关键是如何处理溢出问题
bool add (int a, int b,int *c)
{
*c=a+b;
return (a>0 && b>0 &&(*c<a || *c<b) || (a<0 && b<0 &&(*c>a || *c>b)));
}


分析:
struct bit
{   int a:3;
    int  b:2;
    int c:3;
};
int main()
{
  bit s;
  char *c=(char*)&s;
   cout<<sizeof(bit)<<endl;
  *c=0x99;
   cout << s.a <<endl <<s.b<<endl<<s.c<<endl;
     int a="-1";
   printf("%x",a);
  return 0;
}
输出为什么是
4
1
-1
-4
ffffffff
因为0x99在内存中表示为 100 11 001 , a = 001, b = 11, c = 100
当c为有符合数时, c = 100, 最高1为表示c为负数,负数在计算机用补码表示,所以c = -4;同理
b = -1;
当c为有符合数时, c = 100,即 c = 4,同理 b = 3


位域 :  
有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:    
struct 位域结构名    
{ 位域列表 };   
其中位域列表的形式为: 类型说明符 位域名:位域长度    
例如:    
struct bs   
{   
int a:8;   
int b:2;   
int c:6;   
};   
位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如:    
struct bs   
{   
int a:8;   
int b:2;   
int c:6;   
}data;   
说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明:   

1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:    
struct bs   
{   
unsigned a:4   
unsigned :0 /*空域*/   
unsigned b:4 /*从下一单元开始存放*/   
unsigned c:4   
}   
在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。   

2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。   

3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:    
struct k   
{   
int a:1   
int :2 /*该2位不能使用*/   
int b:3   
int c:2   
};   
从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。   

二、位域的使用位域的使用和结构成员的使用相同,其一般形式为: 位域变量名&#8226;位域名 位域允许用各种格式输出。   
main(){   
struct bs   
{   
unsigned a:1;   
unsigned b:3;   
unsigned c:4;   
} bit,*pbit;   
bit.a=1;   
bit.b=7;   
bit.c=15;   
pri

改错:
#i nclude <stdio.h>

int main(void) {

    int **p;
    int arr[100];

    p = &arr;

    return 0;
}
解答:
搞错了,是指针类型不同,
int **p; //二级指针
&arr; //得到的是指向第一维为100的数组的指针
#i nclude <stdio.h>
int main(void) {
int **p, *q;
int arr[100];
q = arr;
p = &q;
return 0;
}


下面这个程序执行后会有什么错误或者效果:
 #define MAX 255
 int main()
{
   unsigned char A[MAX],i;//i被定义为unsigned char
   for (i=0;i<=MAX;i++)
      A[i]=i;
}
解答:死循环加数组越界访问(C/C++不进行数组越界检查)
MAX=255
数组A的下标范围为:0..MAX-1,这是其一..
其二.当i循环到255时,循环内执行:
  A[255]=255;
这句本身没有问题..但是返回for (i=0;i<=MAX;i++)语句时,
由于unsigned char的取值范围在(0..255),i++以后i又为0了..无限循环下去.

struct name1{
   char  str;
   short x;
   int   num;
}

struct name2{
   char str;
   int num;
   short x;
}

sizeof(struct name1)=8,sizeof(struct name2)=12
在第二个结构中,为保证num按四个字节对齐,char后必须留出3字节的空间;同时为保证整个结构的自然对齐(这里是4字节对齐),在x后还要补齐2个字节,这样就是12字节。

intel:
A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?
static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。
他们都放在数据区,但是编译器对他们的命名是不同的。
如果要使变量在其他模块也有意义的话,需要使用extern关键字。

struct s1
{
  int i: 8;
  int j: 4;
  int a: 3;
  double b;
};

struct s2
{
  int i: 8;
  int j: 4;
  double b;
  int a:3;
};

printf("sizeof(s1)= %d\n", sizeof(s1));
printf("sizeof(s2)= %d\n", sizeof(s2));
result: 16, 24
第一个struct s1
{
  int i: 8;
  int j: 4;
  int a: 3;
  double b;
};
理论上是这样的,首先是i在相对0的位置,占8位一个字节,然后,j就在相对一个字节的位置,由于一个位置的字节数是4位的倍数,因此不用对齐,就放在那里了,然后是a,要在3位的倍数关系的位置上,因此要移一位,在15位的位置上放下,目前总共是18位,折算过来是2字节2位的样子,由于double是8字节的,因此要在相对0要是8个字节的位置上放下,因此从18位开始到8个字节之间的位置被忽略,直接放在8字节的位置了,因此,总共是16字节。

第二个最后会对照是不是结构体内最大数据的倍数,不是的话,会补成是最大数据的倍数上面是基本问题,接下来是编程问题:


本人很弱,这几个题也搞不定,特来求救:
1)读文件file1.txt的内容(例如):
12
34
56
输出到file2.txt:
56
34
12
(逆序)
2)输出和为一个给定整数的所有组合
例如n=5
5=1+4;5=2+3(相加的数不能重复)
则输出
1,4;2,3。
望高手赐教!!

第一题,注意可增长数组的应用.
#i nclude <stdio.h>
#i nclude <stdlib.h>

int main(void)
{
         int MAX = 10;
int *a = (int *)malloc(MAX * sizeof(int));
int *b;
   
FILE *fp1;
FILE *fp2;

fp1 = fopen("a.txt","r");
if(fp1 == NULL)
{printf("error1");
    exit(-1);
}

    fp2 = fopen("b.txt","w");
if(fp2 == NULL)
{printf("error2");
    exit(-1);
}

int i = 0;
    int j = 0;

while(fscanf(fp1,"%d",&a[i]) != EOF)
{
i++;
j++;
if(i >= MAX)
{
MAX = 2 * MAX;
b = (int*)realloc(a,MAX * sizeof(int));
if(b == NULL)
{
printf("error3");
exit(-1);
}
a = b;
}
}

for(;--j >= 0;)
   fprintf(fp2,"%d\n",a[j]);

fclose(fp1);
fclose(fp2);

return 0;


}

第二题.
#i nclude <stdio.h>

int main(void)
{
unsigned long int i,j,k;

printf("please input the number\n");
scanf("%d",&i);
    if( i % 2 == 0)
        j = i / 2;
else
j = i / 2 + 1;

printf("The result is \n");
    for(k = 0; k < j; k++)
     printf("%d = %d + %d\n",i,k,i - k);
return 0;
}

#i nclude <stdio.h>
void main()
{
unsigned long int a,i=1;
scanf("%d",&a);
if(a%2==0)
{
     for(i=1;i<a/2;i++)
     printf("%d",a,a-i);
}
else
for(i=1;i<=a/2;i++)
        printf(" %d, %d",i,a-i);
}

兄弟,这样的题目若是做不出来实在是有些不应该, 给你一个递规反向输出字符串的例子,可谓是反序的经典例程.

void inverse(char *p)
{
    if( *p = = '\0' )
return;
    inverse( p+1 );
    printf( "%c", *p );
}

int main(int argc, char *argv[])
{
    inverse("abc\0");

    return 0;
}

借签了楼上的“递规反向输出”
#i nclude <stdio.h>
void test(FILE *fread, FILE *fwrite)
{
        char buf[1024] = {0};
        if (!fgets(buf, sizeof(buf), fread))
                return;
        test( fread, fwrite );
        fputs(buf, fwrite);
}
int main(int argc, char *argv[])
{
        FILE *fr = NULL;
        FILE *fw = NULL;
        fr = fopen("data", "rb");
        fw = fopen("dataout", "wb");
        test(fr, fw);
        fclose(fr);
        fclose(fw);
        return 0;
}

在对齐为4的情况下
struct BBB
{
   long num;
   char *name;
   short int data;
   char ha;
   short ba[5];
}*p;
p=0x1000000;
p+0x200=____;
(Ulong)p+0x200=____;
(char*)p+0x200=____;
希望各位达人给出答案和原因,谢谢拉
解答:假设在32位CPU上,
sizeof(long) = 4 bytes
sizeof(char *) = 4 bytes
sizeof(short int) = sizeof(short) = 2 bytes
sizeof(char) = 1 bytes

由于是4字节对齐,
sizeof(struct BBB) = sizeof(*p)
= 4 + 4 + 2 + 1 + 1/*补齐*/ + 2*5 + 2/*补齐*/ = 24 bytes  (经Dev-C++验证)

p=0x1000000;
p+0x200=____;
    = 0x1000000 + 0x200*24

(Ulong)p+0x200=____;
    = 0x1000000 + 0x200

(char*)p+0x200=____;
    = 0x1000000 + 0x200*4

你可以参考一下指针运算的细节


写一段程序,找出数组中第k大小的数,输出数所在的位置。例如{2,4,3,4,7}中,第一大的数是7,位置在4。第二大、第三大的数都是4,位置在1、3随便输出哪一个均可。函数接口为:int find_orderk(const int* narry,const int n,const int k)
要求算法复杂度不能是O(n^2)
谢谢!
可以先用快速排序进行排序,其中用另外一个进行地址查找
代码如下,在VC++6.0运行通过。给分吧^-^

//快速排序

#i nclude<iostream>

usingnamespacestd;

intPartition (int*L,intlow,int high)
{
inttemp = L[low];
intpt = L[low];

while (low < high)
{
while (low < high && L[high] >= pt)
--high;
L[low] = L[high];
while (low < high && L[low] <= pt)
++low;
L[low] = temp;
}
L[low] = temp;

returnlow;
}

voidQSort (int*L,intlow,int high)
{
if (low < high)
{
intpl = Partition (L,low,high);

QSort (L,low,pl - 1);
QSort (L,pl + 1,high);
}
}

intmain ()
{
intnarry[100],addr[100];
intsum = 1,t;

cout << "Input number:" << endl;
cin >> t;

while (t != -1)
{
narry[sum] = t;
addr[sum - 1] = t;
sum++;

cin >> t;
}

sum -= 1;
QSort (narry,1,sum);

for (int i = 1; i <= sum;i++)
cout << narry[i] << '\t';
cout << endl;

intk;
cout << "Please input place you want:" << endl;
cin >> k;

intaa = 1;
intkk = 0;
for (;;)
{
if (aa == k)
break;
if (narry[kk] != narry[kk + 1])
{
aa += 1;
kk++;
}

}

cout << "The NO." << k << "number is:" << narry[sum - kk] << endl;
cout << "And it's place is:" ;
for (i = 0;i < sum;i++)
{
if (addr[i] == narry[sum - kk])
cout << i << '\t';
}


return0;
}

1、找错
Void test1()
{
char string[10];
char* str1="0123456789";
strcpy(string, str1);// 溢出,应该包括一个存放'\0'的字符string[11]
}


Void test2()
{
char string[10], str1[10];
for(I=0; I<10;I++)
{
str1[i] ='a';
}
strcpy(string, str1);// I,i没有声明。
}

Void test3(char* str1)
{
char string[10];
if(strlen(str1)<=10)// 改成<10,字符溢出,将strlen改为sizeof也可以
{
strcpy(string, str1);
}
}

2.
void g(int**);
int main()
{
int line[10],i;
int *p=line; //p是地址的地址
for (i=0;i<10;i++)
{
*p=i;
g(&p);//数组对应的值加1
}
for(i=0;i<10;i++)
printf("%d\n",line[i]);
return 0;
}

void g(int**p)
{
(**p)++;
(*p)++;// 无效
}
输出:
1
2
3
4
5
6
7
8
9
10
3. 写出程序运行结果

int sum(int a)
{
auto int c="0";
static int b="3";
c+=1;
b+=2;
return(a+b+c);
}

void main()
{
int I;
int a="2";
for(I=0;I<5;I++)
{
printf("%d,", sum(a));
}
}
// static会保存上次结果,记住这一点,剩下的自己写
输出:8,10,12,14,16,


4.

int func(int a)
{
int b;
switch(a)
{
case 1: 30;
case 2: 20;
case 3: 16;
default: 0
}
return b;
}
则func(1)=?
// b定义后就没有赋值。

5:
int a[3];
a[0]=0; a[1]=1; a[2]=2;
int *p, *q;
p=a;
q=&a[2];
则a[q-p]=a[2]
解释:指针一次移动一个int但计数为1

系统分类: 软件开发  |  用户分类: 编程类  |  标签: 无标签  |  来源: 转贴  | 

点击查看原文

发表评论 阅读全文(370) | 回复(0)

发表于 2008/5/18 13:37:46

1

关于投票

C语言中强制数据类型转换的总结

● 字符型变量的值实质上是一个8位的整数值,因此取值范围一般是-128~127,char型变量也可以加修饰符unsigned,则unsigned char 型变量的取值范围是0~255(有些机器把char型当做unsighed char型对待, 取值范围总是0~255)。
● 如果一个运算符两边的运算数类型不同,先要将其转换为相同的类型,即较低类型转换为较高类型,然后再参加运算,转换规则如下图所示。
double ←── float 高

long

unsigned

int ←── char,short 低
● 图中横向箭头表示必须的转换,如两个float型数参加运算,虽然它们类型相同,但仍要先转成double型再进行运算,结果亦为double型。 纵向箭头表示当运算符两边的运算数为不同类型时的转换,如一个long 型数据与一个int型数据一起运算,需要先将int型数据转换为long型, 然后两者再进行运算,结果为long型。所有这些转换都是由系统自动进行的, 使用时你只需从中了解结果的类型即可。这些转换可以说是自动的,但然,C语言也提供了以显式的形式强制转换类型的机制。
● 当较低类型的数据转换为较高类型时,一般只是形式上有所改变, 而不影响数据的实质内容, 而较高类型的数据转换为较低类型时则可能有些数据丢失。

赋值中的类型转换

当赋值运算符两边的运算对象类型不同时,将要发生类型转换, 转换的规则是:把赋值运算符右侧表达式的类型转换为左侧变量的类型。具体的转换如下:
(1) 浮点型与整型
● 将浮点数(单双精度)转换为整数时,将舍弃浮点数的小数部分, 只保留整数部分。
将整型值赋给浮点型变量,数值不变,只将形式改为浮点形式, 即小数点后带若干个0。注意:赋值时的类型转换实际上是强制的。
(2) 单、双精度浮点型
● 由于C语言中的浮点值总是用双精度表示的,所以float 型数据只是在尾部加0延长为doub1e型数据参加运算,然后直接赋值。doub1e型数据转换为float型时,通过截尾数来实现,截断前要进行四舍五入操作。
(3) char型与int型
● int型数值赋给char型变量时,只保留其最低8位,高位部分舍弃。
● chr型数值赋给int型变量时, 一些编译程序不管其值大小都作正数处理,而另一些编译程序在转换时,若char型数据值大于127,就作为负数处理。对于使用者来讲,如果原来char型数据取正值,转换后仍为正值;如果原来char型值可正可负,则转换后也仍然保持原值, 只是数据的内部表示形式有所不同。
(4) int型与1ong型
● long型数据赋给int型变量时,将低16位值送给int型变量,而将高16 位截断舍弃。(这里假定int型占两个字节)。
将int型数据送给long型变量时,其外部值保持不变,而内部形式有所改变。
(5) 无符号整数
● 将一个unsigned型数据赋给一个占据同样长度存储单元的整型变量时(如:unsigned→int、unsigned long→long,unsigned short→short) ,原值照赋,内部的存储方式不变,但外部值却可能改变。
● 将一个非unsigned整型数据赋给长度相同的unsigned型变量时, 内部存储形式不变,但外部表示时总是无符号的。
/*例:赋值运算符举例 */
main()
{ unsigned a,b;
  int i,j;
  a="65535";
  i="-1";
  j="a";
  b="i";
  printf("(unsigned)%u→(int)%d\n",a,j);
  printf("(int)%d→(unsigned)%u\n",i,b);
}
运行结果为:
(unsigned)65535→(int)-1
(int)-1→(unsigned)65535

● 计算机中数据用补码表示,int型量最高位是符号位,为1时表示负值,为0时表示正值。如果一个无符号数的值小于32768则最高位为0,赋给 int型变量后、得到正值。如果无符号数大于等于32768,则最高位为1, 赋给整型变量后就得到一个负整数值。反之,当一个负整数赋给unsigned 型变量时,得到的无符号值是一个大于32768的值。
● C语言这种赋值时的类型转换形式可能会使人感到不精密和不严格,因为不管表达式的值怎样,系统都自动将其转为赋值运算符左部变量的类型。
● 而转变后数据可能有所不同,在不加注意时就可能带来错误。 这确实是个缺点,也遭到许多人们批评。但不应忘记的是:c面言最初是为了替代汇编语言而设计的,所以类型变换比较随意。当然, 用强制类型转换是一个好习惯,这样,至少从程序上可以看出想干什么。
 

系统分类: 软件开发  |  用户分类: 编程类  |  标签: 无标签  |  来源: 转贴  | 

点击查看原文

发表评论 阅读全文(4941) | 回复(0)

发表于 2008/5/18 11:36:35

1

关于投票

MSP430的软硬件C延时程序设计

MSP430的软硬件C延时程序设计
      MSP430是超低功耗16位单片机,越来越受到电子工程师亲睐并得到广泛应用。C程序直观,可读性好,易于移植和维护,已被很多单片机编程人员所采用。MSP430集成开发环境(如IAR Embedded Workbench和AQ430)都集成了C编译器和C语言级调试器C—SPY。但是C语言难以实现精确延时,这一直困扰着很多MSP430单片机程序员。笔者在实际项目开发过程中,遇到很多需要严格时序控制的接口器件,如单总线数字温度传感器DSl8820、实时时钟芯片PCF8563(需要用普通]/o模拟12C总线时序)、三线制数字电位器AD8402、CF卡(Compact Flash Card)等都需要μs级甚至纳ns级精确延时;而一些慢速设备只需要ms到s级的延时。为此,笔者提出了适合于不同延时级别需要的软件或硬件精确延时方法,并已实际应用,效果良好,大大缩短了开发周期。  

      1  硬件延时 

      MSP430单片机系统程序多采用事件驱动机制,即在没有外部事件触发的情况下CPU休眠于低功耗模式中。当外部事件到来时,产生中断激活CPU,进入相应的中断服务程序(ISR)中。中断响应程序只完成两个任务,一是置位相应事件的标志,二是使MCU退出低功耗模式。主程序负责使MCU在低功耗模式和事件处理程序之间切换,即在主程序中设一个无限循环,系统初始化以后直接进入低功耗模式。MCU被唤醒后,判断各标志是否置位。如果是单一标志置位,那么MCU执行相应的事件处理程序,完成后转入低功耗模式;若是有多个标志同时置位,主程序按照事先排好的消息队列对它们依次判别并进行处理,所有事件处理完毕以后MCU休眠,系统进入低功耗状态(该消息队列的顺序是按照任务的重要性设定的优先级)。在这种前后台系统中,由于主程序是无限循环,就必须关闭看门狗,与其闲置,不如用其定时器的功能作硬件延时。使用MSP430单片机看门狗定时器实现任意时长精确延时,既满足了系统实时低功耗的要求,也弥补了使用无限循环延时的时间难确定和占用CPU时间长的缺点。通过下例,讲解在同一WDT ISR中完成不同时长延时的技巧。

      #pragma vector=WD_r_VECTOR

      interrupt void WDT_Delay(void){

      //看门狗中断服务程序

      if((DelayTime&Delay500ms)==Delay500ms){

      //判断需要500 ms延时的标志是否置位

      static unsigned int n250MS=O;

      n250MS++;

      if(n250MS==2){      //延时250ms×2=500ms

      n250MS=0;      //清零计数器

      DelayTime&=~Delay500ms;//复位标志位

      WDTCTL=WDTHOLD+WDTPW;

      1El&=~WDTlE;//关闭看门狗定时器并禁止其中断

      }

      }

      if((DelayTime&Delay30s)==Delay30s){

      //判断需要的30 s延时标志是否置位

      static unsigned int nS=0;

      nS++;

      if(nS==30){      //延时1 s×30=30 s

      nS=0;      //清零计数器

      DelayTime&=~Delay30s;//复位标志位

      WDTCTL=WDTHOLD+WDTPW;

      IEl&=~WDTlE;  //关闭看门狗定时器并禁止其中断

      }

      }

      }

      如果任务1需要500 ms的延时,只需在需要延时处执行如下语句:

      WDTCTL=WDT_ADLY_250;

      IE┃ =WDTIE;      //①

      DelayTime┃=Delay500ms      //②

      while((DelayTime&Delay500ms)==Delay500ms);  //③

      ①处是配置看门狗工作在定时器模式,WDT每隔250 ms产生一次中断请求。可以根据需要改变时钟节拍,在使用32768 Hz晶振作为时钟源时,可以产生1.9ms、16 ms、250 ms和1000 ms的延时基数。在头文件msp430xl4x.h中,将这4种翻转时间的WDT配置宏定义为:WDT_ADLY_1_9、WDT_ADLY_16、WDT_ADLY_250和WDT_ADLY_1000。如果用DCOCLK作为SMCLK的时钟源,WDT选择SMCLK=1 MHz为时钟源,这样可以有O.064 ms、0.5 ms、8 ms和32 ms延时基数可供使用。

      ②处设置一个标志位,方便WDT ISR判别并进入相应的延时分支。

      ③处一直判别DelayTime标志组中的Delay500ms位,如果处于置位状态,说明所需的延时未到,执行空操作,直到延时时间到,在WDTISR中将Delay500ms复位,跳出while()循环,执行下一条指令。
   
      同理,如果任务2需要30 s延时,通过WDTCTL=WDT_ADLY_1000激活WDT中断,每隔1 s进中断一次,在WDT ISR中判别标志发现是Delay30s置位而不是Delay500ms执行30 s延时程序分支。每中断一次,计数器nS加l,直到计到30,说明30 s延时完成,清零计数器,停止看门狗(WETCTL=WE)THOLD+WDTPW;)可停止产生中断,并复位该延时标志,以通知任务延时时间到,可以执行下面的指令了。
      
      在WDT ISR中可以根据延时基数和计数器的搭配实现任意长度的时间延时。在系统程序设计时,先确定所需的不同延时时间,然后在WDT。ISR中添加相应的延时分支即可。嵌入式实时操作系统μC/OS—II移植于MSP430单片机就是使用看门狗定时器产生时钟节拍的。
      
      对于系统比较简单,只需要单一时长的延时.而又要考虑系统功耗时,介绍另一种使用看门狗定时器中断完成延时的方法。若要延时1 s,则设定WDT每250 ms中断一次。在需要延时处,启动看门狗定时器并允许其中断,系统进入低功耗模式3(共有5种.模式)休眠。在中断服务程序中对延时时间累加,当达到1 s时唤醒CPU,并停止看门狗定时器中断。实例代码如下:

      vold main(vold){

      WDTCTL=WDT_ADT_ADLY_250)

      //启动WDT,每250 ms中断一次

      IEII=WDTIE)//使能看门狗定时器中断

      _BIS_SR(LPM3_bitS+GIE);

      //系统休眠于低功耗模式3,开总中断

      }

      #pragrna vector=WDT_VECTOR

      —interrupt void WDT_Delay(void){  //看门狗中断服务程序

      statlc unsigned charn=4;

      if(一一n==O){      //延时4×250 ms=1 s

      —BlC_SR_IRQ(LPM3_blts);

      //将CPU从低功耗模式3唤醒

      WDTCTL=WDTHOLD+WDTPW:

      IEl&=~WDTIE;)

      //关闭看门狗定时器并禁止其中断

      }
       
      这种方法充分发挥了MSP430系列的超低功耗特性,在等待延时的过程中,CPU不需要一直判断标志位以得知延时结束,而是进入省电模式。等待过程中,只有极短的时间会在中断服务程序中累计时间并进行判断。可以根据需要设置CPU进入不同的低功耗模式LPMx。如果系统使用了多种外设中断,并在其他中断服务程序中也有唤醒CPU的语句,这种方法便不再适用了。
      
      μs级延时不宜使用硬件延时,因为频繁的进出中断会使CPU用大量时间来响应中断和执行中断返回等操作。硬件延时的方法适用于ms级以上的长时间延时。 

      2  软件延时 

      在对数字温度传感器DS18820的操作中,用到的延时有:15 μs、90μs、270 μs、540 μs等。这些延时短暂,占用CPU时间不是太多,所以比较适合软件延时的方法。通过汇编语言编写的程序,很容易控制时间,我们知道每条语句的执行时间,每段宏的执行时间及每段子程序加调用的语句所消耗的时间。因此,要用C语言编制出较为精确的延时程序,就必须研究该段C程序生成的汇编代码。
   
      循环结构延时:延时时间等于指令执行时间与指令循环次数的乘积,举例来讲,对如下延时程序进行实验分析。

      void delay(unsigned int time){

      while(time一一){};
      
      在main()中调用延时函数delayr(n);得到的延时时间是多少,需要在MSP430单片机的集成编译环境IAR Em—bedded Wclrkbeneh IDE 3.10A中编制测试。
      
      使用C430写好一段可执行代码,在其中加入延时函数,并在主函数中调用,以delay(1OO)为例。设置工程选项Options,在Debugger栏中将Drivet选为Simulator,进行软件仿真。在仿真环境C—SPY Debugger中,从菜单View中调出Disassembly和Register窗口,前者显示编程软件根据C语言程序编译生成的汇编程序,在后者窗口中打开CPU Register子窗体,观察指令周期计数器CYCLE—COUNTER。可以看到,delay()编译得到如下代码段:

      delav:

      001112  OF4C mov.w R12,R15

      OOlll4  0C4F mov.w  R15.R12

      001116      3C53  add.w  #0xFFFF.R12

      001118  0F93  tst.w  R15

      00111A  FB23  jne      deIay
      
      单步执行,观察CYCI正COUNTER,发现每执行一条指令,CYCLECOUNTER的值加1,说明这5条指令各占用1个指令周期,循环体while()每执行一次需要5个指令周期,加上函数调用和函数返回各占用3个指令周期,delay(100)延时了5×100+6—506个指令周期。只要知道指令周期,就能容易的计算出延时时长了。延时函数因循环语句和编译器的不同,执行时间也有所不同,依照上述方法具体分析,可以达到灵活编程的目的。
      
      MSP430的指令执行速度即指令所用的周期数,这里的时钟周期指主系统时钟MCLK的周期。单片机上电后,如果不对时钟系统进行设置,默认800 kHz的DCOCLK为MCLK和SMCLK的时钟源,LFXTl接32768 Hz晶体,工作在低频模式(XTS=O)作为ACLK的时钟源。CPU的指令周期由MCLK决定,所以默认的指令周期就是1/800 kHz=1.25μs。要得到lμs的指令周期需要调整DCO频率,即MCLK=1 MHz,只需进行如下设置:BCSCTLl=XT20FF+RSEL2;

      //关闭XT2振荡器,设定DCO频率为1 MHz

      DCOCTL=DCO2

      //使得单指令周期为lμs
   
      并不是说MSP430单片机软件延时最小的延时基准是lμs,当开启XT2=8 MHz高频振荡器,指令周期可以达到125 ns。MSP430F4XX系列的单片机由于采用了增强型锁频环技术FLL+,可以将DCO频率倍增到40MHz,从而得到最快25 ns的指令周期。
  
      调用延时函数的方法适合于100 μs~1 ms之间的延时,100μs以下的短延时最好通过空操作语句_NoP()或其任意个组合来实现。可使用宏定义实现需要的延时,如要延时3 μs,则:

      #define DELAY5US{_NOP();_NOP();_NOP();} 

      结语 

      本文提出的基于MSP430片内看门狗定时器的硬件延时方案和软件延时方法满足了不同时宽级别的延时需求,尤其软件延时,采用汇编程序分析法得到了延时函数准确的延时时间,大大提高了软件延时精确度和程序调试效率,并在多种芯片接口程序中应用,运行效果良好。

系统分类: 软件开发  |  用户分类: 编程类  |  标签: 无标签  |  来源: 无分类  | 

点击查看原文

发表评论 阅读全文(523) | 回复(0)

发表于 2008/5/18 11:22:23

1

关于投票

利用Keil Cx51实现T0的精确定时

利用89C51设计一个简易日历时钟系统,时钟系统硬件主要由单片机控制的计时电路、复位等辅助电路、按键电路、数码管显示电路、电源系统等组成。日历时钟可以显示年、月、时、分、秒;可以设置年、月、时、分。其中计时控制电路由AT89C51单片机控制;按键电路包含时间设置;时间显示屏电路由7个数码管组成;电源系统由小功率整流滤波稳压电路组成,输出直流电压5 V,向主电路及显示电路供电。系统框图如图1所示。

    在计时过程中,系统利用89C51自身的计时器T0作为时钟基准,计时器中断的准确度直接关系到整个系统的精度,因此获取精确的定时时钟信号成为该系统的关键。MCS-51单片机内有2个可编程的16位定时器/计数器,在本系统设计中采用AT89C51的定时器T0,并工作在方式l下,晶振频率为12MHz。

1 T0定时中断
    定时器/计数器T0工作方式1的电路逻辑结构如图2所示。TO定时特性功能寄存器由TL0(低8位)和TH0(高8位)构成。特殊功能寄存器TMOD控制定时寄存器的工作方式;TCON则用于控制定时器T0和T1的启动和停止计数,同时管理定时器TO和T1的溢出标志等。程序开始时需对TL0和TH0进行初始化编程,以定义它们的工作方式,并控制T0和T1的计数。在系统的设计中,计时单位以s为基准,并要求日误差≤10 s,如果用循环去做,无法满足精度要求。选用12 MHz的晶体可得到lμs的精度,经分析确定使用定时器0的方式l。这个方式下 定时器0是16位定时器,也就是最大定时值为jFFFFH,12 MHz晶体的每个定时周期为1 μs,最多可以定时FFFFH×1 μs=65635 μs,即使使用最大值也无法一次定时1 s,设计中使用1次定时20 ms,50次定时中断得到1 s。20 ms定时中断的定时值为:FFFFH-20 ms/l μs=B1DFH[1]. 

2 程序测试与调整
在Keil uVision3平台下利用C语言实现如下代码:
#include<reg52.h>
#define uehar unsigned char
uehar data MScond="0"; //ms
uchar data Scond="0"; //s
uchar data Minure="0"; //rain
uchar data Hollr="0"; //h
void main(void){
EA=1; //允许CPU中断
ET0=1; //定时器0中断打开
TMOD=0xl; //设定时器0为方式1
TH0=0xBl:
TL0=0xDF~ //设定时值为20 000 μs(20 ms)
TR0=1; //开始定时
while(1);
}
void Time0(void)interrupt 1 using 1
{TH0=0xBl; //20 ms断点 (1)
TL0=0xDF; //设定时值
MScond=MScond+1 ;
if(MScond==50)
{MScond=0;
Scond=Scond+1;
if(Seond==60)
{Scond=0;
Minute=Minute+1; //分断点 (2)
if(Minute==60)
{Minute=0;
Hour=Hour+1; //d,时断点 (3)
if(Hour==24)
{Hour=0;}}}}

    首先调试每20 ms中断时的精度,在选项中设定调试晶振为12 MHz,在(1)处设置一个断点再运行,这时记录下每次中断时的时间,如图3所示。在初始化中费时为551 μs,每一次中断时间应该考虑该项的影响。在实际处理中可以利用两次中断时间的差来作为定时器的中断时间间隔。

点击看大图

    通过测试,得到第一次为0.020 568 00 s,第二次为0.040 580 00 s,第三次为0.060 59Z 00 s。可以看出,每中断一次会比定时值长了12 μs。如果将断点设定在(2)处,并通过Logic Analyzer tool,得到分钟第一次中断的时间为60.036 57 s,第二次中断的时间为120.072 57 s,则每分钟的实际时间为60.036 s。再将断点设定在(3)处,得到小时第一次中断的时间为3 602.160 576 s,第二次中断的时间为7 204.320 576 s,可以得到小时的实际时间为3 602.16 s,如图4所示。

点击看大图


    为什么会产生这些误差呢?通过对中断程序的汇编源码进行分析,实际上中断程序入堆栈时使用了两条语句:PUSH ACC和PUSH PSW。执行人栈指令花费了4个机器周期,加上重新对TH0和TL0的加载又用去2个机器周期,计数值加1花费了2个机器周期,中断返回约4个机器周期共约12个机器周期。为了消除这些因素的影响,需要在对T0设置计数值时减去12个机器周期,将计算得到的初始值B1DFH加上12(0CH)得到:B1DFH+12=B1EBH作为新的定时器初值,修改后的程序为:
#include<reg52.h>
#define uchar unsigned char
uchar data MScond="0";//ms
uehar data Seond="0"; //s
uchar data Minute:0; //rain
uchar data Hour="0"; //h
void main(void){
EA=1; //允许CPU中断
ET0=1; //定时器0中断打开
TMOD=Oxl; //设定时器0为方式1
TH0=0xBl;
TL0=OxEB; //设定时值为20 000 μs(20 ms)减去12 μs
TR0=1; //开始定时
while(1);
void Time0(void)interrupt 1 using 1
{TH0=0xBl; //20 ms断点 (1)
TL0=0xDF‘ //设定时值
MSeond=MScond+1:
if(MSeond==50)
{MScond=0;
Seond=Seond+1 ;
if(Scond==60)
{Scond=0;
Minute=Minute+1;//分断点 (2)
if(Minute==60)
{Minure=0;
Hour=Hour+1; I/d,时断点 (3)
if(Hour==24)
{Hour=0;}}}}

    重新调试程序,仍然在选项中设定调试晶振为12 MHz,重新测试20 ms定时器的实际时间,在(1)处设置一个断点后运行,重新记录下每次中断时的时间,如图5所示。初始化时间为556 μs,为消除其影响,使用两次中断时间间隔来作为定时器实际获得的基准时钟。

点击看大图


    得到第一次中断时的时间为0.020 556。O s,第二次为O.040 556 000 s,第三次为0.060 556。O s,可以看出每次中断间隔刚好20 ms。如果将断点设定在(2)处,并通过Logle Analyzer tool,得到第一次中断时时间为60.000 57 s,第二次为120.000 57 s,间隔刚好60 s。将断点设定在(3)处,得到第一次中断的时间为3 600.000 578 s,第二次中断时间为7 200.000 578 s,时间间隔为3 600 s,测试结果如图6所示,完全可以满足系统设计的需要。

点击看大图

3 总结
    通过对定时器的误差分析和校正,可以提高系统的精确度。当然,上面的分析是在软环境下理想晶振频率下实现的,在现实中会因晶振偏差等因素而造成误差[2]。在该测试中,主程序没有进行其他处理,而在日历设计中还要涉及到计时器T1的中断来完成对扫描显示电路的处理,还包括外部中断对时钟进行了调整,加上一些闹钟功能,这必然会对T0的定时精确性产生影响。另外,当中断程序中语句越多,占用的机器周期也越多,因此在设计中应充分利用Keil uVIsion3的分析工具,通过多次调整计数初值以获取精确的时钟信号,这对于要求精确时钟信号的应用具有重要的意义。

系统分类: 软件开发  |  用户分类: 编程类  |  标签: 无标签  |  来源: 转贴  | 

点击查看原文

发表评论 阅读全文(546) | 回复(0)

发表于 2008/1/7 20:44:56

1

关于投票

Keil和Proteus之间的通信设置

如何在keil中调用proteus进行MCU外围器件的仿真!
         proteus 6.9以前的版本
  1、安装keil c51 与 proteus
  2、把proteus安装目录下MODELS文件夹里 VDM51.dll文件复制到Keil安装目录的 \C51\BIN
   目录中。
  3、修改keil安装目录下 Tools.ini文件,在C51字段加入TDRV5=BIN\VDM51.DLL
   ("Proteus VSM Monitor-51 Driver"),保存
   注意:不一定要用TDRV5,根据原来字段选用一个不重复的数值就可以了。引号内的
   名字随意~
  4、打开proteus,画出相应电路(这个自己摸索吧。注意:proteus中mouse的左右键与
   一般程序是相反的样子)。在proteus的tools菜单中选中use remote debug monitor
  5、在keil中编写MCU的程序(keil不会,那先学学吧,比medwin难学些哦!)。
  6、进入KEIL的project菜单option for target '工程名'。在DEBUG选项中右栏上部的下
   拉菜选中 Proteus VSM Monitor-51 Driver
   在进入seting,如果同一台机IP 名为127.0.0.1,如不是同一台机则填另一
   台的IP地址。端口号一定为8000
   注意:可以在一台机器上运行keil,另一台中运行proteus进行远程仿真哦~
  7、在keil中进行debug吧,同时在proteus中查看直观的结果(如LCD显示…) 
 
        proteus 6.9以后的版本
 

proteus 7.12与 keil 8.0的联调方法
    对于proteus 6.9以后的版本,在安装盘里或LABCENTER公司有vdmagdi插件,安装该插件即可实现与KEIL的联调。
    首先安装vdmagdi软件,然后再进行以下设置:

Keil设置
    在Keil软件上单击“Project菜单/Options for Target”选项或者点击工具栏的“option for ta rget”按钮 ,弹出窗口,点击“Debug”按钮,出现如图所示页面。
点击看大图 
在出现的对话框里在右栏上部的下拉菜单里选中“Proteus VSM Monitor-51 Driver”。并且还要点击一下“Use”前面表明选中的小圆点。再点击“Setting”按钮,设置通信接口,在“Host”后面添上“127.0.0.1”,如果使用的不是同一台电脑,则需要在这里添上另一台电脑的IP地址(另一台电脑也应安装Proteus)。在“Port”后面添加“8000”。设置好的情形如图所示,点击“OK”按钮即可。最后将工程编译,进入调试状态,并运行。  

Proteus的设置
进入Proteus的ISIS,鼠标左键点击菜单“Debug”,选中“use romote debuger monitor”,如图所示。此后,便可实现KeilC与Proteus连接调试。
 

系统分类: 软件开发  |  用户分类: 编程类  |  标签: 无标签  |  来源: 转贴  | 

点击查看原文

发表评论 阅读全文(1070) | 回复(0)

发表于 2008/1/7 20:42:06

1

关于投票

Proteus 自建元件库

一、Proteus VSM仿真模型简介

    在使用Proteus仿真单片机系统的过程中,经常找不到所需的元件,这就需要自己编写。Proteus VSM的一个主要特色是使用基于DLL组件模型的可扩展性。这些模型分为两类:电气模型(Electrical Model)和绘图模型(Graphical Model)。电气模型实现元件的电气特性,按规定的时序接收数据和输出数据;绘图模型实现仿真时与用户的交互,例如LCD的显示。一个元件可以只实现电气模型,也可以都实现电气和绘图模型。
    Proteus为VSM模型提供了一些C++抽象类接口,用户创建元件时需要在DLL中实现相应的抽象类。VSM模型和Proteus系统通信的原理如下图: 
点击看大图0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" border="0"> 

绘图模型接口抽象类:

ICOMPONENT――ISIS内部一个活动组件对象,为VSM模型提供在原理图上绘图和用户交互的服务。
IACTIVEMODEL――用户实现的VSM绘图模型要继承此类,并实现相应的绘图和键盘鼠标事件处理。

电气模型接口抽象类:

IINSTANCE――一个PROSPICE仿真原始模型,为VSM模型提供访问属性、模拟节点和数据引脚的服务,还允许模型通过仿真日志发出警告和错误信息。
ISPICECKT(模拟)――SPICE拥有的模拟元件,提供的服务:访问、创建和删除节点,在稀疏矩阵上分配空间,同时还允许模型在给定时刻强制仿真时刻点的发生和挂起仿真。
ISPICEMODEL(模拟)――用户实现的VSM模拟元件要继承此类,并实现相应的载入数据,在完成的时间点处理数据等。
IDSIMCKT(数字)――DSIM拥有的数字元件,提供的服务:访问数字系统的变量,创建回调函数和挂起仿真。
IDSIMMODEL(数字)――用户实现的VSM数字元件要继承此类,并实现相应的引脚状态变化的判断和回调事件的处理。
IDSIMPIN(数字)――数字组件的引脚,提供检测引脚状态和创建输出事务事件的服务。
IDBUSPIN(数字)――数字组件的数据或地址总线,提供检测总线状态和创建总线输出事务事件的服务。
IMIXEDMODEL(混合)――同时继承了ISPICEMODEL 和 IDSIMMODEL,元件既有模拟特性,又有数字特性。

       为了让Proteus访问用户模型中的成员函数,必须创建用户模型的一个实例。这不能通过类的接口来实现,只能通过从DLL中导出几个C函数来实现,在用户模型中必须实现这些C函数,达到构造和析构用户模型实例的效果。

(1)构造和析构绘图模型实例:
IACTIVEMODEL *createactivemodel (CHAR *device, ILICENCESERVER *ils)
VOID deleteactivemodel (IACTIVEMODEL *model)

(2)构造和析构模拟电气模型实例:
ISPICEMODEL *createspicemodel (CHAR *device, ILICENCESERVER *ils)
VOID deletespicemodel (ISPICEMODEL *model)

(3)构造和析构数字电气模型实例:
IDSIMMODEL *createdsimmodel (CHAR *device, ILICENCESERVER *ils)
VOID deletedsimmodel (IDSIMMODEL *model)

(4)构造和析构混合电气模型实例:
IMIXEDMODEL *createmixedmodel (CHAR *device, ILICENCESERVER *ils)
VOID deletemixedmodel (IDSIMMODEL *model)

二、Proteus VSM仿真模型开发流程
1.绘制元件图形、引脚和相关符号。
2.制作元件,设置元件属性。
3.用C++编写元件,实现电气和绘图模型,编译生成DLL。
4.搭建电路仿真测试。

三、VSM模型开发实例
下面以TG19264A点阵式液晶显示元件的开发为实例详细讲解开发过程。

1.打开Proteus,选择菜单 查看>>Snap 10 th,选择左边绘图工具栏的2D graphics box,绘制如图所示的三个图形。


点击看大图0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" border="0"> 

2.选择2D graphics line,给出两条直线,设置width为36th,颜色为灰色。选择2D graphics circle,给四个角绘制安装孔。选择Markers for component origin,给三个图形分别绘图符号原点(图中红色部分)。


点击看大图0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" border="0"> 

3.选择Device pin,顺时针旋转90度,放置20个引脚,如图所示。GND、VCC、V0、Vee、LED+的电气类型选择PP-Power Pin,D/I、R/W、E、CS1、RET、CS2、CS3的电气类型选择IP-Input,D0~D7的电气类型选择IO- Bidirectional。


点击看大图0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" border="0"> 

 

4.右键拖出选择框选择第一个符号,选择菜单库>>制作符号,命名为LCD19264A_C,确定。同理,第二和第三个分别命名为LCD19264A_1 和LCD19264A_0。当用户调用drawsymbol (-1),将绘制LCD19264A_C,调用drawsymbol (1),将绘制LCD19264A_1,调用drawsymbol (0),将绘制LCD19264A_0。


点击看大图0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" border="0"> 

 

5.右键拖出选择框选择符号LCD19264A_C,选择菜单库>>制作元件,Device Properties设置如图,
点击看大图0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" border="0"> 
点击Next>。跳过封装设置,点击Next>。组件属性设置如图,
点击看大图0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" border="0"> 
点击看大图

0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" border="0"> 
点击Next>。选择数据手册(可选),点击Next>。选择器件库,点击OK。

6.打开VC,新建工程,选择Win32 Dynamic-Link Library,给工程命名,建立空的DLL工程。从Proteus安装目录的INCLUDE文件夹中将VSM.HPP复制到当前工程目录,新建文件 LCD19264A.H和LCD19264A.CPP,编写如下代码。


CODE:

/*****************************************************************
* 文件:LCD19264A.H
* 说明:不支持以下特性
* (1) 不支持显示开关控制
* (2) 不支持设置显示起始行
*****************************************************************/
#i nclude "vsm.hpp"

//LCD常量
#define LCD_BLK_NUM  3  //lcd block number
#define LCD_BLK_LEN  64  //lcd block length
#define LCD_LINE_NUM 8  //lcd line number
#define LCD_LENGTH  (LCD_BLK_LEN*LCD_BLK_NUM)  //lcd length
#define LCD_WIDTH  64  //lcd width
#define BLANK_WIDTH  50  //the width of blank
#define SYM_LINEWIDTH 28  //the width of symbol line
//LCD命令掩码
#define CMD_MASK  0xc0
//LCD命令
#define DISP_ONOFF  0x00 //开关背光
#define SET_STARTLINE 0xc0 //设置起始行
#define SET_XADDRESS 0x80 //设置X地址
#define SET_YADDRESS 0x40 //设置Y地址
//延时常量
#define DELAY_1s  1000000000000
#define DELAY_1ms 1000000000
#define DELAY_1us 1000000
#define DELAY_1ns 1000
#define DELAY_1ps 1

/*
LCD元件既有数字电气特性,也有绘图特性,所以要继承IACTIVEMODEL和IDSIMMODEL
*/
class LCD19264A : public IACTIVEMODEL,public IDSIMMODEL
{
public:
/* 电气模型成员函数 */
//数字电路总是返回TRUE
INT isdigital (CHAR *pinname);
//当创建模型实例时被调用,做初始化工作
VOID setup (IINSTANCE *inst, IDSIMCKT *dsim);
//仿真运行模式控制,交互仿真中每帧开始时被调用
VOID runctrl (RUNMODES mode);

//交互仿真时用户改变按键等的状态时被调用
VOID actuate (REALTIME time, ACTIVESTATE newstate);
//交互仿真时每帧结束时被调用,通过传递ACTIVEDATA数据与绘图模型通信,从而调用animate()进行绘图
BOOL indicate (REALTIME time, ACTIVEDATA *data);
//当引脚状态变化时被调用,主要用来处理数据输入和输出
VOID simulate (ABSTIME time, DSIMMODES mode);
//可通过setcallback()设置在给定时间调用的回调函数
VOID callback (ABSTIME time, EVENTID eventid);

/* 绘图模型成员函数 */
//当创建模型实例时被调用,做初始化工作
VOID initialize (ICOMPONENT *cpt);
//被PROSPICE调用,返回模拟电气模型
ISPICEMODEL *getspicemodel (CHAR *device);
//被PROSPICE调用,返回数字电气模型
IDSIMMODEL *getdsimmodel (CHAR *device);
//当原理图需要重绘时被调用
VOID plot (ACTIVESTATE state);
//当相应的电气模型产生活动事件时被调用,常用来更新图形
VOID animate (INT element, ACTIVEDATA *newstate);
//用来处理键盘和鼠标事件
BOOL actuate (WORD key, INT x, INT y, DWORD flags);
private:
IINSTANCE *instance; //PROSPICE仿真原始模型
IDSIMCKT *ckt;   //DSIM的数字元件
ICOMPONENT *component; //ISIS内部一个活动组件对象
//引脚定义
IDSIMPIN *di; //D/I
IDSIMPIN *rw; //R/W
IDSIMPIN *en; //E
IDSIMPIN *cs1; //CS1
IDSIMPIN *cs2; //CS2
IDSIMPIN *cs3; //CS3
IDSIMPIN *d[8]; //D0~D7
IBUSPIN *databus; //D[0..7]
//LCD参数
BYTE x_addr; //X地址(见手册)
BYTE y_addr; //Y地址(见手册)
BYTE status; //状态(见手册)
BYTE cur_blk; //当前块号(总共分3块,见手册)
BYTE DDRAM[LCD_BLK_NUM][LCD_BLK_LEN*LCD_WIDTH/8]; //LCD显示RAM
BOOL new_flag; //新数据到达标志
//显示参数
BOX lcdarea; //LCD显示区域
float pix_width, pix_height; //每象素对应矩形的宽和高
};


CODE:
/*****************************************************************
* 文件:LCD19264A.CPP
* 说明:不支持以下特性
* (1) 不支持显示开关控制
* (2) 不支持设置显示起始行
*****************************************************************/
#i nclude
#i nclude "LCD19264A.h"
//----------------------------------------------------------------------------
//电气模型的实现
//构造数字电气模型实例
extern "C" IDSIMMODEL __declspec(dllexport) * createdsimmodel (CHAR *device, ILICENCESERVER *ils)
{
//授权认证
ils->authorize(0x88888888, 0x69); //版本为6.9
return new LCD19264A; //创建模型实例
}

//析构数字电气模型实例
extern "C" VOID __declspec(dllexport) deletedsimmodel (IDSIMMODEL *model)
{
delete (LCD19264A *)model; //删除模型实例
}

//数字电路总是返回TRUE
INT LCD19264A::isdigital (CHAR *pinname)
{
return 1;
}

//当创建模型实例时被调用,做初始化工作
VOID LCD19264A::setup (IINSTANCE *inst, IDSIMCKT *dsim)
{
instance = inst; //PROSPICE仿真原始模型
ckt = dsim;  //DSIM的数字元件
//获取引脚
di = instance->getdsimpin("D/I,d/i", true);
di->setstate(FLT); //FLOAT
rw = instance->getdsimpin("R/W,r/w", true);
rw->setstate(FLT);
en = instance->getdsimpin("E,e", true);
en->setstate(FLT);
cs1 = instance->getdsimpin("CS1,cs1", true);
cs1->setstate(FLT);
cs2 = instance->getdsimpin("CS2,cs2", true);
cs2->setstate(FLT);
cs3 = instance->getdsimpin("CS3,cs3", true);
cs3->setstate(FLT);
d[0] = instance->getdsimpin("D0,d0", true);
d[0]->setstate(FLT);
d[1] = instance->getdsimpin("D1,d1", true);
d[1]->setstate(FLT);
d[2] = instance->getdsimpin("D2,d2", true);
d[2]->setstate(FLT);
d[3] = instance->getdsimpin("D3,d3", true);
d[3]->setstate(FLT);
d[4] = instance->getdsimpin("D4,d4", true);
d[4]->setstate(FLT);
d[5] = instance->getdsimpin("D5,d5", true);
d[5]->setstate(FLT);
d[6] = instance->getdsimpin("D6,d6", true);
d[6]->setstate(FLT);
d[7] = instance->getdsimpin("D7,d7", true);
d[7]->setstate(FLT);
//为方便操作,将D0~D7映射为8位总线
databus = instance->getbuspin("LCD_DBUS", d, 8);
databus->settiming(100,100,100); //设置时间延迟
databus->setstates(SHI,SLO,FLT); //设置总线逻辑为[1,0,三态]时的驱动状态

//lcd model
x_addr = 0; //X地址(见手册)
y_addr = 0; //Y地址(见手册)
status = 0; //状态(见手册)
new_flag = TRUE; //新数据到达标志
}

//仿真运行模式控制,交互仿真中每帧开始时被调用
VOID LCD19264A::runctrl (RUNMODES mode)
{
}

//交互仿真时用户改变按键等的状态时被调用
VOID LCD19264A::actuate (REALTIME time, ACTIVESTATE newstate)
{

}

//交互仿真时每帧结束时被调用,通过传递ACTIVEDATA数据与绘图模型通信,从而调用animate()进行绘图
BOOL LCD19264A::indicate (REALTIME time, ACTIVEDATA *data)
{
if(new_flag){ //有新数据到达
  data->type = ADT_REAL; //call back animate() to refresh lcd
  data->realval = (float)time*DSIMTICK;
}
return TRUE;
}

//当引脚状态变化时被调用,主要用来处理数据输入和输出
VOID LCD19264A::simulate (ABSTIME time, DSIMMODES mode)
{
BYTE data;
if(en->isnegedge()){  //E的下降沿到达
  if((rw->istate()==SLO)||(rw->istate()==WLO)){ //R/W为低表示写
   //读块选择
   if((cs1->istate()==SLO)||(cs1->istate()==WLO))
    cur_blk = 0;
   else if((cs2->istate()==SLO)||(cs2->istate()==WLO))
    cur_blk = 1;
   else if((cs3->istate()==SLO)||(cs3->istate()==WLO))
    cur_blk = 2;
   else
    return; //not select block
  
   data = (BYTE)databus->getbusvalue(); //读数据
   if((di->istate()==SHI)||(di->istate()==WHI)){ //D/I为高表示数据
    DDRAM[cur_blk][x_addr*LCD_BLK_LEN+y_addr] = data; //写入数据
    new_flag = TRUE; //新数据到达标志
    y_addr = ((y_addr+1)%LCD_BLK_LEN);  //y地址自动加1
    if(y_addr==0)
     x_addr = ((x_addr+1)%LCD_LINE_NUM); //自动换行
   }else{  //D/I为低表示命令
    switch(data&CMD_MASK)
    {
    case DISP_ONOFF: //开关背光
     break;
    case SET_STARTLINE: //设置起始行
     break;
    case SET_XADDRESS: //设置X地址
     x_addr = (data&0x07); //bit2~bit0
     break;
    case SET_YADDRESS: //设置Y地址
     y_addr = (data&0x3f); //bit5~bit0
     break;
    default:
     break;
    }
   }
  }else{  //E的下降沿到达,R/W为高表示读结束
   databus->drivetristate(time); //驱动总线为三态
  }
}else if(en->isposedge()  //E的上升沿到达
   && ((rw->istate()==SHI)||(rw->istate()==WHI))){ //R/W为高表示读
  if((di->istate()==SHI)||(di->istate()==WHI)){ //D/I为高表示数据
   //读块选择
   if((cs1->istate()==SLO)||(cs1->istate()==WLO))
    cur_blk = 0;
   else if((cs2->istate()==SLO)||(cs2->istate()==WLO))
    cur_blk = 1;
   else if((cs3->istate()==SLO)||(cs3->istate()==WLO))
    cur_blk = 2;
   else
    return; //not select block
   data = DDRAM[cur_blk][x_addr*LCD_BLK_LEN+y_addr];
   databus->drivebusvalue(time, data);  //输出数据
   y_addr = ((y_addr+1)%LCD_BLK_LEN);  //y地址自动加1
   if(y_addr==0)
    x_addr = ((x_addr+1)%LCD_LINE_NUM); //自动换行
  }else{  //D/I为低表示命令
   databus->drivebusvalue(time, status); //输出状态
  }
}
}

//可通过setcallback()设置在给定时间调用的回调函数
VOID LCD19264A::callback (ABSTIME time, EVENTID eventid)
{
}

//----------------------------------------------------------------------------
//绘图模型的实现
// Exported constructor for active component models.
extern "C" IACTIVEMODEL __declspec(dllexport) * createactivemodel (CHAR *device, ILICENCESERVER *ils)
{
ils->authorize (0x88888888,0x69); //6.9
return new LCD19264A;
}

// Exported destructor for active component models.
extern "C" VOID  __declspec(dllexport) deleteactivemodel (IACTIVEMODEL *model)
{
delete (LCD19264A *)model;
}

//当创建模型实例时被调用,做初始化工作
VOID LCD19264A::initialize (ICOMPONENT *cpt)
{
//获取ICOMPONENT接口和初始化
component = cpt;
component->setpenwidth(0);
component->setpencolour(BLACK);
component->setbrushcolour(BLACK);
//获取显示区域
component->getsymbolarea(0,&lcdarea);
//计算每象素对应矩形的宽和高
pix_width = (float)(lcdarea.x2-lcdarea.x1-BLANK_WIDTH*2-SYM_LINEWIDTH*2)/LCD_LENGTH;
pix_height = (float)(lcdarea.y2-lcdarea.y1-BLANK_WIDTH*2-SYM_LINEWIDTH*2)/LCD_WIDTH;
}

//被PROSPICE调用,返回模拟电气模型
ISPICEMODEL *LCD19264A::getspicemodel (CHAR *)
{
return NULL;
}

//被PROSPICE调用,返回数字电气模型
IDSIMMODEL  *LCD19264A::getdsimmodel (CHAR *)
{
return this;
}

//当原理图需要重绘时被调用
VOID LCD19264A::plot (ACTIVESTATE state)
{
//绘制LCD19264A_C元件基本图形
component->drawsymbol(-1);
//刷新LCD数据显示
new_flag = TRUE;
animate (0, NULL);
}

//当相应的电气模型产生活动事件时被调用,常用来更新图形
VOID LCD19264A::animate (INT element, ACTIVEDATA *data)
{
BOX pix;
BYTE dat,block,line,byte_off,bit_off;
if(new_flag){ //当有新数据到达
  new_flag = FALSE;
  component->begincache (lcdarea); //打开缓冲
  component->drawsymbol(1);  //显示LCD19264_1符号
  //显示各点数据
  for(block=0; block   for(line=0; line    for(byte_off=0; byte_off     dat = DDRAM[block][line*LCD_BLK_LEN+byte_off]; //get byte data
     for(bit_off=0; bit_off<8; bit_off++){
      if(dat&(1<       pix.x1 = (int)(BLANK_WIDTH+(block*LCD_BLK_LEN+byte_off)*pix_width+0.5);
       pix.y1 = -(int)(BLANK_WIDTH+(line*8+bit_off)*pix_height+0.5);
       pix.x2 = pix.x1 + (int)(pix_width+0.5);
       pix.y2 = pix.y1 - (int)(pix_height+0.5);
       component->drawbox(pix); //绘制1个象素点
      }
     }
    }
   }
  }
  component->endcache(); //结束缓冲,显示数据
}
}

//用来处理键盘和鼠标事件
BOOL LCD19264A::actuate (WORD key, INT x, INT y, DWORD flags) 
{
return FALSE;
}

7.搭建电路如下电路,新建Keil C工程,编写代码测试元件。如下图:
点击看大图0 && image.height>0){if(image.width>=510){this.width=510;this.height=image.height*510/image.width;}}" border="0">

系统分类: 软件开发  |  用户分类: 编程类  |  标签: 无标签  |  来源: 转贴  | 

点击查看原文

发表评论 阅读全文(2762) | 回复(5)

发表于 2007/1/6 14:42:01

9

关于投票

gcc白皮书

大家觉得好的帮顶下。谢谢pdf

系统分类: 嵌入式  |  用户分类: 编程类  |  标签: 无标签  |  来源: 转贴  | 

点击查看原文

发表评论 阅读全文(952) | 回复(0)

Total , Page /