这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【转载】C/C++嵌入式笔试题(二)----from三叶

共1条 1/1 1 跳转至

【转载】C/C++嵌入式笔试题(二)----from三叶

工程师
2023-11-19 21:10:41     打赏

中断(Interrupts)

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

__interrupt double compute_area (double radius)
{
     double area = PI * radius * radius;
     printf(" Area = %f", area);
     return area;
}

这个函数有太多的错误了,以至让人不知从何说起了:
1). ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。
2). ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。
3). 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。
4). 与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。

代码例子(Code examples)

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

void foo(void)
{
     unsigned int a = 6;
     int b = -20;
     (a+b > 6) puts("> 6") : puts("<= 6");
}

这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是 “>6”。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。

13. 评价下面的代码片断:

unsigned int zero = 0;
unsigned int compzero = 0xFFFF;
/*1's complement of zero */

对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下:

unsigned int compzero = ~0;

这一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的经验里,好的嵌入式程序员非常准确地明白硬件的细节和它的局限,然而PC机程序往往把硬件作为一个无法避免的烦恼。
到了这个阶段,应试者或者完全垂头丧气了或者信心满满志在必得。如果显然应试者不是很好,那么这个测试就在这里结束了。但如果显然应试者做得不错,那么我就扔出下面的追加问题,这些问题是比较难的,我想仅仅非常优秀的应试者能做得不错。提出这些问题,我希望更多看到应试者应付问题的方法,而不是答案。不管如何,你就当是这个娱乐吧…

动态内存分配(Dynamic memory allocation)

14. 尽管不像非嵌入式计算机那么常见,嵌入式系统还是有从堆(heap)中动态分配内存的过程的。那么嵌入式系统中,动态分配内存可能发生的问题是什么?

这里,我期望应试者能提到内存碎片,碎片收集的问题,变量的持行时间等等。这个主题已经在ESP杂志中被广泛地讨论过了(主要是 P.J. Plauger, 他的解释远远超过我这里能提到的任何解释),所有回过头看一下这些杂志吧!让应试者进入一种虚假的安全感觉后,我拿出这么一个小节目:下面的代码片段的输出是什么,为什么?

char *ptr;
if ((ptr = (char *)malloc(0)) == NULL)
puts("Got a null pointer");
else
puts("Got a valid pointer");

这是一个有趣的问题。最近在我的一个同事不经意把0值传给了函数malloc,得到了一个合法的指针之后,我才想到这个问题。这就是上面的代码,该代码的输出是“Got a valid pointer”。我用这个来开始讨论这样的一问题,看看被面试者是否想到库例程这样做是正确。得到正确的答案固然重要,但解决问题的方法和你做决定的基本原理更重要些。

Typedef

15. Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子:
#define dPS struct s *
typedef struct s * tPS;

以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么?
这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭喜的。答案是:typedef更好。思考下面的例子:
dPS p1,p2;
tPS p3,p4;

第一个扩展为
struct 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。


1、请定义一个宏,比较两个数a、b的大小,不能使用大于、小于、if语句

#define Max(a,b) ( a/b)?a:b

2、如何输出源文件的标题和目前执行行的行数

int line = __LINE__;

char *file = __FILE__;

cout<<"file name is "<<(file)<<",line is "<

3、两个数相乘,小数点后位数没有限制,请写一个高精度算法

4、写一个病毒

while (1)

{

int *p = new int[10000000];

}

5、不使用额外空间,将 A,B两链表的元素交*归并

6、将树序列化 转存在数组或 链表中

struct st{

int i;

short s;

char c;

};

sizeof(struct st);

7、

char * p1;

void * p2;

int p3;

char p4[10];

sizeof(p1...p4) =?

8、

4,4,4,10

二分查找

快速排序

双向链表的删除结点
 
1。主键用于唯一标识表中的行数据,一个主键值对应一行数据。另外,会自动在主键上创建索引,用于加快查询。
2。外键用于两个表的联系。两个表必须具有相同类型的属性,在该属性上有相同的值。该属性应为其中一个表的主键,在另外一个表设置为外键。

主键:唯一标识,不能为空,加快查询速度,自动创建索引,
外键:约束内表的数据的更新,从定义外键时可以发现 外键是和主键表联系,数据类型要统一,长度(存储大小)要统一。这样在更新数据的时候会保持一致性。
索引能将数据按一定的规则进行排列这样进行查询时能很快定位数据,从而加快查询的速度,
但不合适的索引将导致INSERT或UPDATE很慢


#include<stdio.h>
#include<stdlib.h>

int   main(void)
{
       union A{
         char a;
         char y:3;
         char z:3;
         char x:2;
       }a;

       a.a = 0x67;
       printf("a.a =%0x a.x=%0x \t a.y=%0x\t a.z=%0x\n",a.a, a.x, a.y, a.z );
       return 0;
}
结果
a.a =67 a.x=ffffffff     a.y=ffffffff a.z=ffffffff
a.a =64 a.x=0 a.y=fffffffc a.z=fffffffc
a.a =65 a.x=1 a.y=fffffffd a.z=fffffffd

很久没动c语言了,很多基础性的东西都没有深入学习。今天看到关于联合体位域面试题,想了半天才知道程序答案的来由~~汗颜~~
如果单从位域来理解这个还是简单,问题的关键是理解其在计算机内的存取规则。
对a.a=64, 单从取位(二进制)上可知a.x=00, a.y=101, a.z=101.目前通用计算机x86大都是32位机,我的机器也是32位,在存取上默认是存取32位。对每个数而言第一位是符号位,补码存储。那么可以理解a.x的补码就是00000000, a.y的补码就是11111100, a.z的补码就是11111100.这样看比较自然,但如果输出结果是10进制,就会觉得难以理解。当然关键还是对数据的存取规则和编码的熟悉。
a.a=0x64的10进制结果是a.x=0, a.y=-4 ,a.z=-4
补充一点,union内的变量顺序对结果不影响(每次只可能有一种解释是合理的,这个跟struct显然不同)

关于位域在结构体的应用主要要注意内存对齐规则的理解和空域的理解
http://blog.csdn.net/jiyucn/archive/2006/07/01/862085.aspx
使用位域的主要目的是压缩存储,其大致规则为:
1)   如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2)   如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3)   如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
4)   如果位域字段之间穿插着非位域字段,则不进行压缩;
5)   整个结构体的总大小为最宽基本类型成员大小的整数倍。

#include <stdio.h>
int main()
{
union
{
            struct
            {
                     unsigned short s1:3;
                     unsigned short s2:3;
                     unsigned short s3:3;
            }x;
            char c;
}v;
v.c=100;

printf("%d\n",sizeof(v));
printf("s1=%d\n",v.x.s1);
printf("s2=%d\n",v.x.s2);
printf("s3=%d\n",v.x.s3);
return 0;
}
fc6--linux下gcc-4.1.1
2
s1=4
s2=4
s3=5
windows xp2下vc6.0
2
s1=4
s2=4
s3=1

可见s3的结果并不一样vc6.0的结果如果只是按位取,就很好理解,这样跟之前的union的存取规则又不一样了~~而对于gcc-4.1.1,s3=5还没想出该结果的原因。同时考虑
struct
            {
                     unsigned short s1:3;
                     unsigned short s2:3;
                     unsigned short s3:3;
    unsigned short s4:7;
            }x;
   最后s4的结果更加扑朔迷离~~请大家多指点~·
#include<stdio.h>
#include<stdlib.h>

int   main(void)
{
       union A{
         char a;
         char y:3;
         char z:3;
         char x:2;
       }a;

       a.a = 0x67;
       printf("a.a =%0x a.x=%0x \t a.y=%0x\t a.z=%0x\n",a.a, a.x, a.y, a.z );
       return 0;
}
结果
a.a =67 a.x=ffffffff     a.y=ffffffff a.z=ffffffff
a.a =64 a.x=0 a.y=fffffffc a.z=fffffffc
a.a =65 a.x=1 a.y=fffffffd a.z=fffffffd

很久没动c语言了,很多基础性的东西都没有深入学习。今天看到关于联合体位域面试题,想了半天才知道程序答案的来由~~汗颜~~
如果单从位域来理解这个还是简单,问题的关键是理解其在计算机内的存取规则。
对a.a=64, 单从取位(二进制)上可知a.x=00, a.y=101, a.z=101.目前通用计算机x86大都是32位机,我的机器也是32位,在存取上默认是存取32位。对每个数而言第一位是符号位,补码存储。那么可以理解a.x的补码就是00000000, a.y的补码就是11111100, a.z的补码就是11111100.这样看比较自然,但如果输出结果是10进制,就会觉得难以理解。当然关键还是对数据的存取规则和编码的熟悉。
a.a=0x64的10进制结果是a.x=0, a.y=-4 ,a.z=-4
补充一点,union内的变量顺序对结果不影响(每次只可能有一种解释是合理的,这个跟struct显然不同)

关于位域在结构体的应用主要要注意内存对齐规则的理解和空域的理解
http://blog.csdn.net/jiyucn/archive/2006/07/01/862085.aspx
使用位域的主要目的是压缩存储,其大致规则为:
1)   如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2)   如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3)   如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
4)   如果位域字段之间穿插着非位域字段,则不进行压缩;
5)   整个结构体的总大小为最宽基本类型成员大小的整数倍。

#include <stdio.h>
int main()
{
union
{
            struct
            {
                     unsigned short s1:3;
                     unsigned short s2:3;
                     unsigned short s3:3;
            }x;
            char c;
}v;
v.c=100;

printf("%d\n",sizeof(v));
printf("s1=%d\n",v.x.s1);
printf("s2=%d\n",v.x.s2);
printf("s3=%d\n",v.x.s3);
return 0;
}
fc6--linux下gcc-4.1.1
2
s1=4
s2=4
s3=5
windows xp2下vc6.0
2
s1=4
s2=4
s3=1

可见s3的结果并不一样vc6.0的结果如果只是按位取,就很好理解,这样跟之前的union的存取规则又不一样了~~而对于gcc-4.1.1,s3=5还没想出该结果的原因。同时考虑
struct
            {
                     unsigned short s1:3;
                     unsigned short s2:3;
                     unsigned short s3:3;
    unsigned short s4:7;
            }x;
   最后s4的结果更加扑朔迷离~~请大家多指点~·


C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static。前者应用于普通变量和函数,不涉及类;后者主要说明static在类中的作用。

来源: 整理文章为传播相关技术,网络版权归原作者所有,如有侵权,请联系删除。


共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]