现在嵌入式发展这么快,很多人都开始走上嵌入式学习之路。据市场统计,一些毕业或者正在找工作的人在面试企业的时候会被卡在这里,那就是面试题。很多人在面试中都表现得很好,但是在回答面试问题时却没有付出足够的努力,最终被面试问题拒绝了,这使得找工作成为了一个难题,让他们无路可走。天赋。而且,对于某些人来说也是如此。综上所述,你可以通过嵌入式访谈向一些空难受害者学习。公司面试一般都是可以的。
(1)char * constp char const *p const char *p 以上三者有什么区别?
回答:
字符*常量p; //常量指针,p的值不能修改
字符常量* p; //指向常量的指针,所指向的常量值不能改变const char *p; //和char const *p
char * const p 是一个char 指针。指针是一个常量,不能修改。也就是说,像p=q 这样的陈述是错误的;
char const * p 和const char * p 是同一类型的char 指针。指针指向的字符被视为常量,不允许修改。也就是说,像*p=q 这样的语句是错误的。
(2)char str1[]='abc'; charstr2[]='abc'; const char str3[]='abc'; const charstr4[]='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是指针,它们指向同一个常量区。
关于嵌入式物联网,确实有很多东西需要学习。不要学错路线和内容,导致你的薪资水涨船高!
我免费给大家分享一个数据包,差不多150G。学习内容、面试、项目都比较新、全面!据估计,在网上购买某种鱼至少要花费几十美元。
点此找助手0元获取:扫码进群获取资料
(3)什么是预编译以及什么时候需要预编译:
回答:
1. 始终使用不经常更改的大型代码体。
2. 程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,所有包含文件都可以预编译成预编译头。
预编译指令表示编译器在程序正式编译之前执行的操作,可以放置在程序中的任何位置。
(4)下面代码中的两个sizeof用法有问题吗?
[Cyi] void UpperCase( char str[] ) //将str 中的小写字母转换为大写字母{ for( size_t i=0; i
(5) 嵌入式系统中经常使用无限循环。 C语言中如何编写无限循环?
这个问题有多种解决方案。我的首选解决方案是:
同时(1)
{
}
一些程序员更喜欢以下解决方案:
为了(;)
{
}
这个实现让我很困惑,因为语法并不能准确表达正在发生的事情。如果候选人给出
作为解决方案,我将以此为契机来探索他们是如何做到这一点的
基本的。如果他们的基本答案是:“我被教导要这样做,但从未想过为什么。”
给我留下不好的印象。
第三种选择是使用goto
循环:
.
转到循环;
如果候选人给出了上述解决方案,则意味着他要么是一名汇编语言程序员(这可能是一件好事),要么他
我是一名BASIC/FORTRAN 程序员,想要进入一个新领域。
常量
(6)关键字const是什么意思?
当我听到受访者说“const 意味着恒定”时,我就知道我正在与一个业余爱好者打交道。
去年Dan Saks在他的文章中已经完整总结了const的所有用法,所以ESP(译者:Embedded)
每个系统编程的读者都应该非常熟悉const 能做什么和不能做什么。如果你来自
如果不阅读那篇文章,只要能够知道const 意味着“只读”就可以了。虽然这个答案并不完整
答案,但我接受它作为正确答案。 (如果想知道更详细的答案,请仔细阅读Saks
文章。 )如果候选人能够正确回答这个问题,我会问他一个附加问题:以下所有陈述
什么意思
常量整型;
int 常量a;
常量int *a;
int * 常量a;
int const * 一个常量;
前两者作用相同,a是常整数。第三个表示a 是一个指向常量整数的指针(也
也就是说,整数不能修改,但指针可以)。第四个含义a 是指向整数的常量指针(也
也就是说,指针指向的整数可以修改,但指针不能修改)。最后一位表示a是1
指向常整数的常指针(即指针所指向的整数不能被修改,指针也不能被修改。
可修改)。如果候选人能够正确回答这些问题,那么他或她就给我留下了良好的印象。顺便一提
总而言之,你可能会问,即使不使用const关键字,仍然很容易写出功能正确的程序,那么
为什么我还是这么看重const这个关键字呢?我有以下几个原因:
1)。关键字const的作用是向阅读你代码的人传达非常有用的信息。事实上,它声明了一个参数。
它是一个常量,告诉用户该参数的应用目的。如果您曾经花费大量时间清理别人的垃圾
垃圾,你很快就会学会欣赏这些额外的信息。 (当然,懂得使用const的程序员很少会留下垃圾
让其他人清理垃圾。 )
2)。使用const 关键字可以通过为优化器提供一些附加信息来生成更紧凑的代码。
3)。合理使用关键字const可以让编译器自然地保护那些不想改变的参数,防止它们被改变。
被无意的代码修改。简而言之,这减少了错误的发生。
易挥发的
(7) 关键字volatile 的含义是什么并给出三个不同的例子。
定义为volatile 的变量意味着该变量可能会被意外改变,这样编译器就不会
假设该变量的值。准确地说,优化器每次使用该变量时都必须仔细地重新读取该变量。
获取该变量的值,而不是使用存储在寄存器中的备份。以下是易失性变量的一些示例:
1)。并行设备的硬件寄存器(如状态寄存器)
2)。将在中断服务程序中访问的非自动变量(非自动变量)
3)。多线程应用程序中多个任务共享的变量
不能回答这个问题的人将不会被录用。我认为这是C 程序员与嵌入式系统程序员最大的区别
基本问题。嵌入式系统程序员经常与硬件、中断、RTOS等打交道,所有这些都需要vo
纬度变量。不了解易失性内容可能会导致灾难。
假设受访者正确回答了这个问题(好吧,怀疑情况确实如此),我将深入挖掘一下,看看
让我们看看这个人是否完全理解volatility 的重要性。
1)。参数可以同时是const 和volatile 吗?解释为什么。
2)。指针可以是易失性的吗?解释为什么。
3)。以下函数有什么问题:
int square(易失性int *ptr)
{
返回*ptr * *ptr;
}
答案如下:
1)。是的。只读状态寄存器就是一个例子。它是不稳定的,因为它可能会发生意外的改变。
它是const,因为程序不应该尝试修改它。
2)。是的。虽然这种情况并不常见。一个例子是当服务例程修改指向缓冲区的指针时
指针。
3)。这段代码中有一个技巧。这段代码的目的是返回指针*ptr所指向的值的平方。然而,通过
由于*ptr指向一个易失性参数,编译器将生成类似以下的代码:
int square(易失性int *ptr)
{
整数a,b;
a=*ptr;
b=*ptr;
返回a*b;
}
由于*ptr 的值可能会意外更改,因此a 和b 可能会不同。因此,此代码可能不会返回
是您期望的平方值!正确的代码如下:
长方形(易失性int *ptr)
{
整数a;
a=*ptr;
返回a*a;
}
位操作
(8)嵌入式系统总是要求用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码
,第一个设置a 的位3,第二个清除a 的位3。上述两个操作中,其他位保持不变。
对于这个问题有三个基本的回答
1)。不知道如何开始。接受采访的人从未做过任何嵌入式系统工作。
2)。使用位域。位域是被扔进C语言死胡同的东西。它确保您的代码可以在不同的编译器中运行。
它们之间不可移植,并且还确保您的代码不可重用。我最近很不幸地见到了英飞凌
为其更复杂的通信芯片编写的驱动程序使用位字段,因此对我来说完全没用,因为我的程序员
翻译器以其他方式实现位字段。道德上:永远不要让一个非嵌入式人员留下来
国际硬件优势。
3)。使用#defines 和位掩码进行操作。这是一种非常便携的方法,应该使用
方法。最佳解决方案如下:
#定义BIT3 (0x1 3)
静态整型;
无效set_bit3(无效)
{
一个|=位3;
}
无效清除_bit3(无效)
{
a=~BIT3;
}
有些人喜欢定义一个用于设置和清除值的掩码并定义一些描述性常量,这也是可以接受的。
我想看到一些要点:常量、|=和=~ 操作的解释。
数据声明
(9) 利用变量a给出如下定义
a) 一个整数
b) 指向整数的指针
c) 指向指针的指针,它指向的指针是一个整数(Apointertoapointer
为整数)
d) 10 个整数的数组
e) 一个由10 个整数指针组成的数组
整数)
f) 指向10 个整数的数组的指针
g) 指向一个函数的指针,该函数接受一个整数参数并返回一个整数(Apointertoafu
以整数作为参数并返回整数的函数)
h) 一个由10 个指针组成的数组,指向一个采用整数参数并返回整数的函数
一个由十个指针组成的数组,指向采用整数参数和r 的函数
返回一个整数)
答案是:
a)整数a; //一个整数
b)整数*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 个指针组成的数组,这些指针指向采用int 的函数
eger 参数并返回一个整数
人们经常声称这里的一些问题需要翻一本书才能回答,我同意。当我
在写这篇文章时,我确实检查了书以确保语法正确。
但当我接受采访时,我希望被问到这个问题(或类似的问题)。因为在接受采访时
有一段时间,我确信我知道这个问题的答案。如果候选人不知道
所有的答案(或者至少是大部分的答案),那么就没有为这次面试做准备。如果面试官没有
为了准备这次采访,他可以做哪些准备呢?
静止的
(10)关键字static的作用是什么
这个简单的问题很少得到完整的回答。在C语言中,关键字static有三个明显的作用:
1)。在函数体中,声明为static 的变量在调用函数时保持其值。
2)。在模块内部(但在函数体外部),声明为static 的变量可以被模块中使用的函数访问,
但不能被模块外的其他函数访问。它是一个局部全局变量。
3)。在模块内,声明为静态的函数只能由该模块中的其他函数调用。也就是说,这个
函数仅限于声明它的模块的本地范围。
大多数考生能正确回答第一部分,有些人能正确回答第二部分,很少有人能理解第二部分。
三个部分。对于显然不了解本地化数据和代码范围的好处的候选人来说,这是一个严重的缺点
和重要性。
(11) 对于32位机器,该机器的指针是多少位?回答:
只需查看地址总线中的位数即可确定指针有多少位。 80386以后的机器都使用32条数据总线。所以指针的位数是4个字节。
(12) 主函数()
{
inta[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]。
(13)下面的代码有什么问题:
int main() { 字符;字符*str=a; strcpy(str,'你好'); printf(str);返回0; }
答:没有为str分配内存空间,会出现异常。问题在于将字符串复制到字符变量指针指向的地址中。虽然可以正确输出结果,但由于固有读写越界,导致程序崩溃。
(14)char* s='AAA'; printf('%s',s); s[0]='B'; printf('%s',s);怎么了?
答案:“AAA”是一个字符串常量。 s是一个指针,指向这个字符串常量,所以声明s的时候有问题。成本char*s='AAA';并且由于它是一个常量,所以对s[0]的赋值操作是非法的。