无线网络优化工程师(长沙亚讯网络科技有限公司)

首先,你的专业是什么?最好是做通信和计算机方面的无线网络优化,这样你会有一些网络的基础知识。

其次,这个专业要求你对无线移动网络有一定的了解,比如基本的网络结构,基本理论,基本概念。但是不一定要精通,因为入行还要再学习,要看你做的方向,比如2g或者3g。

再次,你要对电脑有基本的了解,最好是笔记本,这是网络优化的标配。会用excel,在网络优化、数据库等中高时期会很重要。如果后期能简单编程就更好了,这是高手的要求。

最后,你要能吃苦,能长期出差,能适应恶劣的条件。

另外,如果你能问出这样的问题,就去专业论坛看看大家都说了些什么。建议使用mscbsc和c114。

软件工程师编写测试问题

#定义秒/年(60 * 60 * 24 * 365)UL

我想看看这里的一些东西:

1).#定义语法基础知识(比如不能以分号结尾,括号的使用等。)

2)知道预处理器会为你计算常量表达式的值,所以直接写你是如何计算一年中的秒数的,而不是计算实际值,这样更清楚,也更无成本。

3).要认识到这个表达式会溢出一个16位机器的整数——所以用长整数符号L告诉编译器这个常数是长整数。

4)如果你在表达式中使用UL(无符号长整型),那么你有一个很好的起点。记住,第一印象很重要。

2.编写一个“标准”宏MIN,它输入两个参数并返回较小的一个。

#定义MIN(A,B)((A)& lt;= (B) (A) : (B))

该测试旨在实现以下目的:

1).识别宏中#define应用的基本知识。这非常重要,因为在内联操作符成为标准C语言的一部分之前,宏是方便地生成嵌入式代码的唯一方法。对于嵌入式系统,为了达到所需的性能,嵌入式代码通常是必要的。

2).三条件运算符的知识。这个运算符之所以存在于C语言中,是因为它使编译器能够生成比if-then-else更优化的代码。理解这种用法很重要。

3).知道如何在宏中将参数小心地括在括号中。

4).我也用这个问题来讨论宏的副作用,比如:你写下面这段代码会怎么样?

least = MIN(*p++,b);

3.预处理程序标识#error的目的是什么?

如果不知道答案,请看参考1。这个问题对于区分正常哥们和书呆子很有用。只有书呆子才会阅读C语言教科书的附录来找出这样的东西。

问题的答案。当然,如果你找的不是书呆子,那么候选人最好希望他不知道答案。

无限循环(无限循环)

4.无限循环经常在嵌入式系统中使用。用C语言怎么写无限循环?

这个问题有几种解决方法。我的第一选择是:

while(1) { }

一些程序员更喜欢下面的方案:

for(;;) { }

这个实现让我很尴尬,因为这个语法并没有准确地表达出正在发生的事情。如果一个候选人把这作为一个计划,我会把这作为一个机会来探索他们做什么。

基本原则。如果他们的基本回答是:“有人教我这么做,但我从没想过为什么。”这会给我留下不好的印象。

第三种方案是使用goto。

循环:

...

转到循环;

如果考生给出了上述方案,说明他要么是汇编语言程序员(这可能是好事),要么是想进入新领域的BASIC/FORTRAN程序员。

数据声明(数据声明)

5.使用变量A给出以下定义

a)整数。

b)指向整数的指针。

c)指针指向指针,指针指向整数(指针指向整数的指针)

d)10个整数的数组。

e)有10个指针的数组,指针指向一个整数(10个指针指向整数的数组)。

f)指向10整数数组的指针。

g)指向有整数参数并返回整数的函数的指针(指向以整数为自变量并返回整数的函数的指针)。

h)一个数组,有10个指针指向一个函数,该函数有一个整数形参并返回一个整数(十个指针的数组指向采用整数形参并返回一个整数的函数)。

答案是:

a)int a;//整数

b)int * a;//指向整数的指针

c)int * * a;//指向整数指针的指针

d)int a[10];//10个整数的数组

e)int * a[10];//指向整数的10个指针的数组

f)int(* a)[10];//指向10整数数组的指针

g)int(* a)(int);//指向采用整数参数并返回整数的函数A的指针

h)int(* a[10])(int);//10个指针的数组,这些指针指向采用整数参数并返回整数的函数

人们常常声称,这里有几个问题只有翻书才能回答。我同意这种说法。当我写这篇文章时,我确实查阅了这本书以确保语法正确。

但是面试的时候,我就料到会被问到这个问题(或者类似的问题)。因为面试的时候,我肯定知道这个问题的答案。如果候选人不知道

全部回答(或者至少大部分回答),那么这次面试就没有准备。如果面试官没有为这次面试做准备,那他为什么可以准备?

静态

6.关键字static的作用是什么?

很少有人能完整回答这个简单的问题。在C语言中,关键字static有三个明显的功能:

1).在函数体中,声明为static的变量在调用该函数的过程中保持其值不变。

2).在模块内部(但在函数外部),声明为静态的变量可以被模块中使用的函数访问,但不能被模块外部的其他函数访问。它是一个局部全局变量。

3).在模块中,声明为静态的函数只能被该模块中的其他函数调用。也就是说,这个函数被限制在声明它的模块的局部范围内。

大部分考生能正确回答第一部分,有些能正确回答第二部分,很少有人能理解第三部分。这是一个考生的严重缺点,因为他显然不明白本地化数据和代码范围的好处和重要性。

常数

7.关键字const是什么意思?

一听到被面试者说“const就是不变的意思”,我就知道我在和一个外行打交道。去年,Dan Saks在他的文章中完整地总结了const的所有用法,所以每一个ESP(译者:嵌入式系统编程)的读者都应该非常熟悉const能做什么,不能做什么。如果你从来没看过文章,就说const是“只读”的意思。虽然这个答案不是一个完整的答案,但我接受它为正确答案。如果你想知道更详细的答案,请仔细阅读萨克斯的文章。如果考生能正确回答这个问题,我会额外问他一个问题:下面这些说法是什么意思?

const int a;

int const a;

const int * a;

int * const a;

int const * a const

前两者作用相同,A为常数整数。第三个意思是a是一个常量整数的指针(也就是整数不能修改,但是指针可以)。第四个含义A是一个常量指针,指向一个整数(即指针指向的整数可以修改,但指针不能修改)。最后一个表示a是一个常量指针,指向一个常量整数(即指针指向的整数不能修改,指针也不能修改)。如果候选人能正确回答这些问题,那么他给我留下了很好的印象。对了,你可能会问,就算不用关键字const,用正确的函数写程序还是很容易的,那我为什么那么看重关键字const呢?我也有以下原因:

1).关键字const的作用是向阅读你的代码的人传达非常有用的信息。其实把一个参数声明为常量就是告诉用户这个参数的应用目的。如果你花了很多时间清理别人留下的垃圾,你很快就会学会欣赏这些额外的信息。(当然,懂得使用const的程序员很少会把垃圾留给别人清理。)

2)通过给优化器一些附加信息,使用关键字const可以产生更紧凑的代码。

3).合理使用关键字const可以使编译器自然地保护那些不想被改变的参数,防止它们被代码无意地修改。简而言之,这样可以减少bug的发生。

不稳定的

8.关键字volatile的意思是什么,并给出三个不同的例子。

定义为volatile的变量意味着该变量可能会被意外更改,因此编译器不会采用该变量的值。准确地说,优化器必须在每次使用这个变量时仔细地重新读取它的值,而不是使用存储在寄存器中的备份。以下是一些易变变量的例子:

1).并行设备的硬件寄存器(如状态寄存器)。

2)将在中断服务子程序中访问的非自动变量。

3).多线程应用程序中多个任务共享的变量。

不会回答这个问题的人不会被录用。我觉得这是区分C程序员和嵌入式系统程序员最基本的问题。嵌入式系统程序员经常要处理硬件、中断、RTOS等等,这些都需要易变变量。不理解易变的内容会带来灾难。

假设受访者正确回答了这个问题(好吧,我怀疑是否会是这样),我会深入挖掘一下,看看这个人是否真正理解了volatile的全部重要性。

1).参数可以是常量也可以是变量吗?解释原因。

2).指针可以是易变的吗?解释原因。

3).以下函数有什么问题:

int square(volatile int *ptr)

{

return * ptr * * ptr

}

以下是答案:

1).是的。只读状态寄存器就是一个例子。它是易变的,因为它可能会被意外地改变。它是常量,因为程序不应该试图修改它。

2).是的。虽然这不是很常见。一个例子是当服务子例程将指针固定到缓冲区时。

3).这段代码中有一个恶作剧。这段代码的目的是返回指针*ptr指向的值的平方,但是由于*ptr指向一个可变参数,编译器将生成类似于下面的代码:

int square(volatile int *ptr)

{

int a,b;

a = * ptr

b = * ptr

返回a * b;

}

由于*ptr的值可能会意外改变,因此A和B可能不同。因此,这段代码可能不会返回您期望的平方值!正确的代码如下:

长正方形(可变int *ptr)

{

int a;

a = * ptr

返回a * a

}

位操作

9.嵌入式系统总是要求用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一段设置a的位3,第二段清零a的位3,在上面两个操作中,保持其他位不变。

对这个问题有三种基本反应。

1).我不知道如何开始。被套没做过什么嵌入式系统的工作。

2).使用位域。Bit fields是被扔进C语言死角的东西,它保证了你的代码在不同编译器之间不可移植,同时也保证了你的代码不可重用。最近看到英飞凌为其复杂的通信芯片写的驱动,用了位域,对我完全没用,因为我的编译器是用其他方式实现位域的。从道德上讲:永远不要让一个非嵌入式的家伙粘在实际硬件的边缘。

3).使用#定义和位掩码进行操作。这是一种高度可移植的方法,应该使用。最佳解决方案如下:

# define bit 3(0x 1 & lt;& lt3)

静态int a;

void set_bit3(void)

{

a | = BIT3

}

void clear_bit3(void)

{

a & amp= ~ BIT3

}

有些人喜欢定义一个掩码和一些解释常量来设置和清除值,这是可以接受的。我想看几点:解释常数,| =和&;= ~操作。

访问固定的内存位置。

10.嵌入式系统通常要求程序员访问特定的内存位置。在一个项目中,需要将绝对地址为0x67a9的整型变量的值设置为0xaa66。该编译器是一个纯ANSI编译器。编写代码来完成这项任务。

这个问题测试你是否知道为了访问一个绝对地址把一个整数转换成一个指针是合法的。实现这个问题的方式因个人风格而异。典型的类似代码如下:

int * ptr

ptr =(int *)0x67a 9;

* ptr = 0x aa 55;

一个更隐晦的方法是:

*(int * const)(0x67a 9)= 0x aa 55;

即使你的口味更接近第二个选项,我也建议你在面试中使用第一个选项。

中断(中断)

11.中断是嵌入式系统的重要组成部分,这导致许多编译器开发者提供了一个扩展——让标准C支持中断。代表性的事实是产生了一个新的关键字__interrupt。以下代码使用__interrupt关键字来定义中断服务子例程(ISR)。请评论这段代码。

_ _中断double compute_area(双半径)

{

双面积= PI *半径*半径;

printf(" Area = %f ",Area);

返回区域;

}

这个函数错误太多,让人不知从何下手:

1).ISR无法返回值。如果你不明白这一点,那么你不会被录用。

2).ISR无法传递参数。如果你没有看到这一点,你被录用的机会和第一个是一样的。

3).在许多处理器/编译器中,浮点通常是不可重入的。有些处理器/编译器需要堆叠额外的寄存器,有些处理器/编译器就是不允许ISR中的浮点运算。另外,ISR要短小高效,在ISR中做浮点运算是不明智的。

4).与第三点一致,printf()经常出现重入和性能问题。如果你输了第三第四点,我也不会太难为你。不用说,如果你能做到最后两点,你的就业前景会越来越光明。

代码示例

12.下面的代码输出是什么,为什么?

void foo(空)

{

无符号int a = 6;

int b =-20;

(a+b & gt;6)看跌期权(" & gt6 "):puts(" & lt;= 6");

}

这个问题测试你是否了解C语言的整数自动转换原理,我发现有些开发者对这些东西知之甚少。无论如何,这个无符号整数问题的答案是输出是“>:6”。原因是当表达式中存在有符号类型和无符号类型时,所有操作数都会自动转换为无符号类型。所以,-20变成了一个很大的正整数,所以这个表达式计算出来的结果大于6。这对于经常使用无符号数据类型的嵌入式系统非常重要。如果你回答错了这个问题,你就有可能得不到这份工作。

13.评估以下代码片段:

无符号int zero = 0;

无符号整数compzero = 0xFFFF

/*1的零补码*/

对于int类型不是16位的处理器,上述代码是不正确的。应该这样写:

无符号整数comp zero = ~ 0;

这个问题确实能揭示出考生是否理解处理器字长的重要性。以我的经验来看,好的嵌入式程序员对硬件的细节及其局限性理解得非常准确,但PC程序往往把硬件当成无法回避的烦恼。

在这个阶段,候选人要么完全沮丧,要么信心十足,志在必得。如果很明显考生不是很优秀,那么测试到这里就结束了。但是如果很明显考生做的很好,那么我就抛出下面的补充问题,比较难。我觉得只有非常优秀的考生才能做好。通过问这些问题,我希望看到更多的是考生的应对方式,而不是答案。反正就当这是娱乐吧…

动态内存分配(动态内存分配)

14.虽然没有非嵌入式计算机那么普遍,但是嵌入式系统还是有从堆中动态分配内存的过程。那么嵌入式系统中动态内存分配可能存在哪些问题呢?

在这里,我预计考生会提到内存碎片、碎片收集、变量的持有时间等等。这个话题在ESP杂志(主要是P.J. Plauger,他的解释远远超过我在这里能提到的任何东西)上讨论的很广泛,所以回头看看这些杂志!让考生输入一个虚假的安全感后,我拿出了这样一个小程序:下面这段代码片段的输出是什么,为什么?

char * ptr

if((ptr =(char *)malloc(0))= = NULL)

puts("得到一个空指针");

其他

puts("得到一个有效的指针");

这是一个有趣的问题。最近我才想到这个问题,直到我的一个同事无意间把0的值传递给了函数malloc,得到了一个合法的指针。这就是上面的代码,这段代码的输出是“得到了一个有效的指针”。我以此来展开对这样一个问题的讨论,看看被采访者是否认为图书馆的常规这样做是对的。得到正确的答案很重要,但解决问题的方法和你决策的基本原则更重要。

Typedef

15.Typedef在C语言中经常用于声明现有数据类型的同义词。你也可以用预处理器做类似的事情。例如,考虑下面的例子:

#定义dPS结构*

typedef结构s * tPS

以上两种情况的意图都是将dPS和tPS定义为指向结构s的指针,哪种方法更好?(如果有的话)为什么?

这是一个很微妙的问题,任何答对这个问题的人(正当原因)都应该受到祝贺。答案是:typedef更好。考虑下面的例子:

dPS p1,p2;

tPS p3、P4;

第一个扩展是

结构s * p1,p2;

上面的代码将p1定义为指向结构的指针,将p2定义为实际结构,这可能不是您想要的。第二个例子正确地定义了两个指针p3和p4。

16.c语言赞同一些令人震惊的结构。以下结构合法吗?如果有,它是做什么的?

int a = 5,b = 7,c;

c = a+++b;

这个问题将会是这次考试的圆满结局。信不信由你,上面的例子完全符合语法。问题是编译器如何处理它?低级编译器实际上会争论这个问题,根据最大处理原则,编译器应该能够尽可能处理所有合法的用法。因此,上述代码被处理为:

c = a+++b;

所以这个码后面是a = 6,b = 7,c = 12+02。