|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
Model的改变最好通过Notification来传播之前吃过这样的亏最好不要用delegate模式)UIViewController C言语测试是雇用嵌进式体系程序员过程当中必需并且无效的办法。这些年,我既列入也构造了很多这类测试,在这过程当中我意想到这些测试能为口试者和被口试者供应很多有效信息,别的,撇开口试的压力不谈,这类测试也是相称风趣的。
从被口试者的角度来说,你能懂得很多关于出题者或监考者的情形。这个测试只是出题者为显现其对ANSI尺度细节的常识而不是手艺技能而计划吗?这是个愚昧的成绩吗?如要你答出某个字符的ASCII值。这些成绩侧重考查你的体系挪用和内存分派战略方面的才能吗?这标记着出题者大概花工夫在微机上而不是在嵌进式体系上。假如上述任何成绩的谜底是"是"的话,那末我晓得我得仔细思索我是不是应当往做这份事情。
从口试者的角度来说,一个测试大概能从多方面展现招考者的本质:最基础的,你能懂得招考者C言语的程度。不论怎样,看一下此人怎样回覆他不会的成绩也是满风趣。招考者是以好的直觉做出明智的选择,仍是只是瞎蒙呢?当招考者在某个成绩上卡住时是找托言呢,仍是体现出对成绩的真实的猎奇心,把这当作进修的时机呢?我发明这些信息与他们的测试成就一样有效。
有了这些设法,我决意出一些真正针对嵌进式体系的考题,但愿这些使人头痛的考题能给正在找事情的人一点匡助。这些成绩都是我这些年实践碰着的。个中有些题很难,但它们应当都能给你一点启发。
这个测试适于分歧程度的招考者,年夜多半低级程度的招考者的成就会很差,履历丰厚的程序员应当有很好的成就。为了让你能本人决意某些成绩的偏好,每一个成绩没有分派分数,假如选择这些考题为你所用,请自行按你的意义分派分数。
预处置器(Preprocessor)
1.用预处置指令#define声明一个常数,用以标明1年中有几秒(疏忽闰年成绩)
#defineSECONDS_PER_YEAR(60*60*24*365)UL
我在这想看到几件事变:
1)#define语法的基础常识(比方:不克不及以分号停止,括号的利用,等等)
2)明白预处置器将为你盘算常数表达式的值,因而,间接写出你是怎样盘算一年中有几秒而不是盘算出实践的值,是更明晰而没有价值的。
3)意想到这个表达式将使一个16位机的整型数溢出-因而要用到长整型标记L,告知编译器这个常数是的长整型数。
4)假如你在你的表达式顶用到UL(暗示无标记长整型),那末你有了一个好的出发点。记着,第一印象很主要。
2.写一个"尺度"宏MIN,这个宏输出两个参数并前往较小的一个。
#defineMIN(A,B)((A)<=(B)(A):(B))
这个测试是为上面的目标而设的:
1)标识#define在宏中使用的基础常识。这是很主要的。由于在嵌进(inline)操纵符变成尺度C的一部分之前,宏是便利发生嵌进代码的独一办法,关于嵌进式体系来讲,为了能到达请求的功能,嵌进代码常常是必需的办法。
2)三重前提操纵符的常识。这个操纵符存在C言语中的缘故原由是它使得编译器能发生比if-then-else更优化的代码,懂得这个用法是很主要的。
3)明白在宏中当心地把参数用括号括起来
4)我也用这个成绩入手下手会商宏的反作用,比方:当你写上面的代码时会产生甚么事?
least=MIN(*p++,b);
3.预处置器标识#error的目标是甚么?
假如你不晓得谜底,请看参考文献1。这成绩对辨别一个一般的伴计和一个书白痴是很有效的。只要书白痴才会读C言语教材的附录往找出象这类成绩的谜底。固然假如你不是在找一个书白痴,那末招考者最好但愿本人不要晓得谜底。
逝世轮回(Infiniteloops)
4.嵌进式体系中常常要用到无穷轮回,你怎样用C编写逝世轮回呢?
这个成绩用几个办理计划。我首选的计划是:
while(1)
{
}
一些程序员更喜好以下计划:
for(;;)
{
}
这个完成体例让我难堪,由于这个语法没有切实表到达底怎样回事。假如一个招考者给出这个作为计划,我将用这个作为一个时机往探求他们如许做的基础道理。假如他们的基础谜底是:"我被教着如许做,但从没有想到过为何。"这会给我留下一个坏印象。
第三个计划是用goto
Loop:
...
gotoLoop;
招考者如给出下面的计划,这申明大概他是一个汇编言语程序员(这大概是功德)大概他是一个想进进新范畴的BASIC/FORTRAN程序员。
数据声明(Datadeclarations)
5.用变量a给出上面的界说
a)一个整型数(Aninteger)
b)一个指向整型数的指针(Apointertoaninteger)
c)一个指向指针的的指针,它指向的指针是指向一个整型数(Apointertoapointertoanintege)r
d)一个有10个整型数的数组(Anarrayof10integers)
e)一个有10个指针的数组,该指针是指向一个整型数的。(Anarrayof10pointerstointegers)
f)一个指向有10个整型数数组的指针(Apointertoanarrayof10integers)
g)一个指向函数的指针,该函数有一个整型参数并前往一个整型数(Apointertoafunctionthattakesanintegerasanargumentandreturnsaninteger)
h)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并前往一个整型数(Anarrayoftenpointerstofunctionsthattakeanintegerargumentandreturnaninteger)
谜底是:
a)inta;//Aninteger
b)int*a;//Apointertoaninteger
c)int**a;//Apointertoapointertoaninteger
d)inta[10];//Anarrayof10integers
e)int*a[10];//Anarrayof10pointerstointegers
f)int(*a)[10];//Apointertoanarrayof10integers
g)int(*a)(int);//Apointertoafunctionathattakesanintegerargumentandreturnsaninteger
h)int(*a[10])(int);//Anarrayof10pointerstofunctionsthattakeanintegerargumentandreturnaninteger
人们常常宣称这里有几个成绩是那种要翻一下书才干回覆的成绩,我批准这类说法。当我写这篇文章时,为了断定语法的准确性,我切实其实查了一下书。可是当我被口试的时分,我希冀被问到这个成绩(大概邻近的成绩)。由于在被口试的这段工夫里,我断定我晓得这个成绩的谜底。招考者假如不晓得一切的谜底(或最少年夜部分谜底),那末也就没无为此次口试做筹办,假如该口试者没无为此次口试做筹办,那末他又能为何出筹办呢?
Static
6.关头字static的感化是甚么?
这个复杂的成绩很少有人能回覆完整。在C言语中,关头字static有三个分明的感化:
1)在函数体,一个被声明为静态的变量在这一函数被挪用过程当中保持其值稳定。
2)在模块内(但在函数体外),一个被声明为静态的变量能够被模块内所用函数会见,但不克不及被模块外别的函数会见。它是一个当地的全局变量。
3)在模块内,一个被声明为静态的函数只可被这一模块内的别的函数挪用。那就是,这个函数被限定在声明它的模块的当地局限内利用。
年夜多半招考者能准确回覆第一部分,一部分能准确回覆第二部分,同是很少的人能明白第三部分。这是一个招考者的严峻的弱点,由于他明显不明白当地化数据和代码局限的优点和主要性。
Const
7.关头字const有甚么含义?
我只需一听到被口试者说:"const意味着常数",我就晓得我正在和一个专业者打交道。客岁DanSaks已在他的文章里完整归纳综合了const的一切用法,因而ESP(译者:EmbeddedSystemsProgramming)的每位读者应当十分熟习const能做甚么和不克不及做甚么.假如你从没有读到那篇文章,只需能说出const意味着"只读"就能够了。只管这个谜底不是完整的谜底,但我承受它作为一个准确的谜底。(假如你想晓得更具体的谜底,细心读一下Saks的文章吧。)
假如招考者能准确回覆这个成绩,我将问他一个附加的成绩:
上面的声明都是甚么意义?
constinta;
intconsta;
constint*a;
int*consta;
intconst*aconst;
/******/
前两个的感化是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不成修正的,但指针能够)。第四个意义a是一个指向整型数的常指针(也就是说,指针指向的整型数是能够修正的,但指针是不成修正的)。最初一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不成修正的,同时指针也是不成修正的)。假如招考者能准确回覆这些成绩,那末他就给我留下了一个好印象。顺带提一句,大概你大概会问,即便不必关头字const,也仍是能很简单写出功效准确的程序,那末我为何还要云云垂青关头字const呢?我也以下的几下来由:
1)关头字const的感化是为给读你代码的人转达十分有效的信息,实践上,声明一个参数为常量是为了告知了用户这个参数的使用目标。假如你曾花良多工夫清算别的人留下的渣滓,你就会很快学会感激这点过剩的信息。(固然,明白用const的程序员很少会留下的渣滓让他人来清算的。)
2)经由过程给优化器一些附加的信息,利用关头字const大概能发生更松散的代码。
3)公道地利用关头字const可使编译器很天然地回护那些不但愿被改动的参数,避免其被偶然的代码修正。简而言之,如许能够削减bug的呈现。
Volatile
8.关头字volatile有甚么含义并给出三个分歧的例子。
一个界说为volatile的变量是说这变量大概会被意想不到地改动,如许,编译器就不会往假定这个变量的值了。准确地说就是,优化器在用到这个变量时必需每次都当心地从头读取这个变量的值,而不是利用保留在存放器里的备份。上面是volatile变量的几个例子:
1)并行设备的硬件存放器(如:形态存放器)
2)一其中断服务子程序中会会见到的非主动变量(Non-automaticvariables)
3)多线程使用中被几个义务共享的变量
回覆不出这个成绩的人是不会被雇佣的。我以为这是辨别C程序员和嵌进式体系程序员的最基础的成绩。弄嵌进式的家伙们常常同硬件、中止、RTOS等等打交道,一切这些都请求用到volatile变量。不明白volatile的内容将会带来劫难。
假定被口试者准确地回覆了这是成绩(嗯,嫌疑是不是会是如许),我将略微穷究一下,看一下这家伙是否是直正明白volatile完整的主要性。
1)一个参数既能够是const还能够是volatile吗?注释为何。
2);一个指针能够是volatile吗?注释为何。
3);上面的函数有甚么毛病:
intsquare(volatileint*ptr)
{
return*ptr**ptr;
}
上面是谜底:
1)是的。一个例子是只读的形态存放器。它是volatile由于它大概被意想不到地改动。它是const由于程序不该该试图往修正它。
2);是的。只管这其实不很罕见。一个例子是当一其中服务子程序修该一个指向一个buffer的指针时。
3)这段代码有点反常。这段代码的目标是用来返指针*ptr指向值的平方,可是,因为*ptr指向一个volatile型参数,编译器将发生相似上面的代码:
intsquare(volatileint*ptr)
{
inta,b;
a=*ptr;
b=*ptr;
returna*b;
}
因为*ptr的值大概被意想不到地该变,因而a和b多是分歧的。了局,这段代码大概返不是你所希冀的平方值!准确的代码以下:
longsquare(volatileint*ptr)
{
inta;
a=*ptr;
returna*a;
}
位操纵(Bitmanipulation)
9.嵌进式体系老是要用户对变量或存放器举行位操纵。给定一个整型变量a,写两段代码,第一个设置a的bit3,第二个扫除a的bit3。在以上两个操纵中,要坚持别的位稳定。
对这个成绩有三种基础的反响
1)不晓得怎样动手。该被面者从没做过任何嵌进式体系的事情。
2)用bitfields。Bitfields是被扔到C言语逝世角的工具,它包管你的代码在分歧编译器之间是不成移植的,同时也包管了的你的代码是不成重用的。我比来不幸看到Infineon为其较庞大的通讯芯片写的驱动程序,它用到了bitfields因而完整对我无用,由于我的编译器用别的的体例来完成bitfields的。从品德讲:永久不要让一个非嵌进式的家伙粘实践硬件的边。
3)用#defines和bitmasks操纵。这是一个有极高可移植性的办法,是应当被用到的办法。最好的办理计划以下:
#defineBIT3(0x1<<3)
staticinta;
voidset_bit3(void)
{
a|=BIT3;
}
voidclear_bit3(void)
{
a&=~BIT3;
}
一些人喜好为设置和扫除值而界说一个掩码同时界说一些申明常数,这也是能够承受的。我但愿看到几个要点:申明常数、|=和&=~操纵。
会见流动的内存地位(Accessingfixedmemorylocations)
10.嵌进式体系常常具有请求程序员往会见某特定的内存地位的特性。在某工程中,请求设置一相对地点为0x67a9的整型变量的值为0xaa66。编译器是一个地道的ANSI编译器。写代码往完成这一义务。
这一成绩测试你是不是晓得为了会见一相对地点把一个整型数强迫转换(typecast)为一指针是正当的。这一成绩的完成体例跟着团体作风分歧而分歧。典范的相似代码以下:
int*ptr;
ptr=(int*)0x67a9;
*ptr=0xaa55;
Amoreobscureapproachis:
一个较流畅的办法是:
*(int*const)(0x67a9)=0xaa55;
即便你的咀嚼更靠近第二种计划,但我倡议你在口试时利用第一种计划。
中止(Interrupts)
11.中止是嵌进式体系中主要的构成部分,这招致了良多编译开辟商供应一种扩大—让尺度C撑持中止。具代表现实是,发生了一个新的关头字__interrupt。上面的代码就利用了__interrupt关头字往界说了一其中断服务子程序(ISR),请批评一下这段代码的。
__interruptdoublecompute_area(doubleradius)
{
doublearea=PI*radius*radius;
printf("Area=%f",area);
returnarea;
}
这个函数有太多的毛病了,以致让人不知从何提及了:
1)ISR不克不及前往一个值。假如你不懂这个,那末你不会被招聘的。
2)ISR不克不及传送参数。假如你没有看到这一点,你被招聘的时机同等第一项。
3)在很多的处置器/编译器中,浮点一样平常都是不成重进的。有些处置器/编译器必要让额处的存放器进栈,有些处置器/编译器就是不同意在ISR中做浮点运算。别的,ISR应当是短而无效率的,在ISR中做浮点运算是不明智的。
4)与第三点一脉相承,printf()常常有重进和功能上的成绩。假如你丢失落了第三和第四点,我不会太难堪你的。不必说,假如你能失掉后两点,那末你的被招聘远景愈来愈光亮了。
代码例子(Codeexamples)
12.上面的代码输入是甚么,为何?
voidfoo(void)
{
unsignedinta=6;
intb=-20;
(a+b>6)puts(">6"):puts("<=6");
}
这个成绩测试你是不是明白C言语中的整数主动转换准绳,我发明有些开辟者明白少少这些工具。不论怎样,这无标记整型成绩的谜底是输入是">6"。缘故原由是当表达式中存在有标记范例和无标记范例时一切的操纵数都主动转换为无标记范例。因而-20酿成了一个十分年夜的正整数,以是该表达式盘算出的了局年夜于6。这一点关于应该频仍用到无标记数据范例的嵌进式体系来讲是丰常主要的。假如你答错了这个成绩,你也就到了得不到这份事情的边沿。
13.评价上面的代码片段:
unsignedintzero=0;
unsignedintcompzero=0xFFFF;
/*1"scomplementofzero*/
关于一个int型不是16位的处置器为说,下面的代码是不准确的。应编写以下:
unsignedintcompzero=~0;
这一成绩真正能揭发出招考者是不是明白处置器字长的主要性。在我的履历里,好的嵌进式程序员十分正确地分明硬件的细节和它的范围,但是PC机程序常常把硬件作为一个没法制止的懊恼。
到了这个阶段,招考者大概完整无精打采了大概信念满满志在必得。假如明显招考者不是很好,那末这个测试就在这里停止了。但假如明显招考者做得不错,那末我就扔出上面的追加成绩,这些成绩是对照难的,我想仅仅十分优异的招考者能做得不错。提出这些成绩,我但愿更多看到招考者对付成绩的办法,而不是谜底。不论怎样,你就当是这个文娱吧...
静态内存分派(Dynamicmemoryallocation)
14.只管不像非嵌进式盘算机那末罕见,嵌进式体系仍是有从堆(heap)中静态分派内存的历程的。那末嵌进式体系中,静态分派内存大概产生的成绩是甚么?
这里,我希冀招考者能提到内存碎片,碎片搜集的成绩,变量的持行工夫等等。这个主题已在ESP杂志中被普遍地会商过了(次要是P.J.Plauger,他的注释远远凌驾我这里能提到的任何注释),一切回过火看一下这些杂志吧!让招考者进进一种子虚的平安感到后,我拿出这么一个大节目:
上面的代码片断的输入是甚么,为何?
char*ptr;
if((ptr=(char*)malloc(0))==NULL)
puts("Gotanullpointer");
else
puts("Gotavalidpointer");
这是一个风趣的成绩。比来在我的一个同事不经意把0值传给了函数malloc,失掉了一个正当的指针以后,我才想到这个成绩。这就是下面的代码,该代码的输入是"Gotavalidpointer"。我用这个来入手下手会商如许的一成绩,看看被口试者是不是想到库例程如许做是准确。失掉准确的谜底当然主要,但办理成绩的办法和你做决意的基础道理更主要些。
Typedef
15Typedef在C言语中频仍用以声明一个已存在的数据范例的同义字。也能够用预处置器做相似的事。比方,思索一下上面的例子:
#definedPSstructs*
typedefstructs*tPS;
以上两种情形的企图都是要界说dPS和tPS作为一个指向布局s指针。哪一种办法更好呢?(假如有的话)为何?
这是一个十分奇妙的成绩,任何人答对这个成绩(合法的缘故原由)是应该被祝贺的。谜底是:typedef更好。思索上面的例子:
dPSp1,p2;
tPSp3,p4;
第一个扩大为
structs*p1,p2;
.
下面的代码界说p1为一个指向布局的指,p2为一个实践的布局,这大概不是你想要的。第二个例子准确地界说了p3和p4两个指针。
流畅的语法
16.C言语批准一些使人震动的布局,上面的布局是正当的吗,假如是它做些甚么?
inta=5,b=7,c;
c=a+++b;
这个成绩将做为这个检验的一个兴奋的开头。不论你相不信任,下面的例子是完整符合语法的。成绩是编译器怎样处置它?程度不高的编译作者实践上会争辩这个成绩,依据最处置准绳,编译器应该能处置尽量一切正当的用法。因而,下面的代码被处置成:
c=a+++b;
因而,这段代码持行后a=6,b=7,c=12。
假如你晓得谜底,或猜出准确谜底,做得好。假如你不晓得谜底,我也不把这个看成成绩。我发明这个成绩的最年夜优点是这是一个关于代码编写作风,代码的可读性,代码的可修正性的好的话题。
好了,伴计们,你如今已做完一切的测试了。这就是我出的C言语测试题,我怀着兴奋的心境写完它,但愿你以一样的心境读完它。假如是以为这是一个好的测试,那末只管都用到你的找事情的过程当中往吧。天晓得大概过个一两年,我就不做如今的事情,也必要找一个。
相干浏览:
嵌进式开辟—C言语口试题
以后一定会坚持多读些相关的书籍,在这里也要感谢一下“清源教育”的老师对我学习中极大的帮助,每次有不懂得问题,都及时得到了他们的回答。 |
|