培训体系培训资料.docx
《培训体系培训资料.docx》由会员分享,可在线阅读,更多相关《培训体系培训资料.docx(24页珍藏版)》请在冰豆网上搜索。
培训体系培训资料
(培训体系)培训资料
新人培训阶段学习资料
上海核心信息技术XX公司
Version0.02(2011.03)
课程介绍1
课程大纲2
第壹阶段Linux开发基础2
第二阶段嵌入式C语言编程强化3
第三阶段Linux用户态开发8
第四阶段Linux内核态及驱动开发10
第五阶段软件开发流程11
课程介绍
本课程旨于发现具备开发Linux下驱动程序的人才,新入社员将通过壹个月的时间参照本教程熟悉Linux下设备驱动开发必须的知识。
培训结束后符合要求的新人将进入公司具体项目组熟悉具体项目的开发方法。
课程大纲
本课程大纲内列出的任务基本由员工自己动手解决为主,通常每天上午指导人员将进行昨日实验结果评价及当日任务安排,对于工作任务不清楚的地方请及时向指导人员提出。
下午主要为新员工个人实验时间。
第壹阶段Linux开发基础
2-3天
通过本课程的学习,使新员工能够了解Linux操作系统的概念,熟练掌握Linux下的基本命令、常用工具的使用方面的知识。
学习内容:
◆公司安全保密教育,日报格式说明
◆Linux常用命令,文本编辑器Vi,简单Shell脚本编程
◆嵌入式Linux开发环境基础:
Gcc,Gdb,Make和Makefile
GCCARM编译环境安装(SourceryG++LiteEditionforARM)
◆软件版本管理器Svn
◆嵌入式软件开发环境搭建和使用
x86linux内核编译
versatilearmlinux内核编译
QEMU运行linux
实验:
1.开发环境配置,安装ubuntu虚拟机,熟悉Linux使用
2.配置X86开发环境,编译x86Linux内核,于QEMU下运行
3.配置ARM开发环境,编译armLinux内核,于QEMU下运行
4.编写HelloWorld程序,于x86/armLinuxQEMU下运行
5.编写壹个脚本,统计壹个目录下面所有C代码的行数。
6.这些格式的如何去解压
.tar/bz2/tar.bz2/tar.gz/tar.tar/.Z/.zip/.rar
第二阶段嵌入式C语言编程强化
3-5天
本课程的主要目标是通过编写代码的方式,加强对于C语言编程和数据结构的掌握程度。
回答如下16道国外经典的面向嵌入式C语言面试题
1.用预处理指令#define声明壹个常数,用以表明1年中有多少秒(忽略闰年问题)
2.写壹个“标准”宏MIN,这个宏输入俩个参数且返回较小的壹个。
3.预处理器标识#error的目的是什么?
4.嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?
5.用变量a给出下面的定义
a)壹个整型数(Aninteger)
b)壹个指向整型数的指针(Apointertoaninteger)
c)壹个指向指针的的指针,它指向的指针是指向壹个整型数(Apointertoapointertoaninteger)
d)壹个有10个整型数的数组(Anarrayof10integers)
e)壹个有10个指针的数组,该指针是指向壹个整型数的(Anarrayof10pointerstointegers)
f)壹个指向有10个整型数数组的指针(Apointertoanarrayof10integers)
g)壹个指向函数的指针,该函数有壹个整型参数且返回壹个整型数(Apointertoafunctionthattakesanintegerasanargumentandreturnsaninteger)
h)壹个有10个指针的数组,该指针指向壹个函数,该函数有壹个整型参数且返回壹个整型数(Anarrayoftenpointerstofunctionsthattakeanintegerargumentandreturnaninteger)
6.关键字static的作用是什么?
7.关键字const是什么含意?
8.关键字volatile有什么含意且给出三个不同的例子。
9.嵌入式系统总是要用户对变量或寄存器进行位操作。
给定壹个整型变量a,写俩段代码,第壹个设置a的bit3,第二个清除a的bit3。
于之上俩个操作中,要保持其它位不变。
10.嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。
于某工程中,要求设置壹绝对地址为0x67a9的整型变量的值为0xaa66。
编译器是壹个纯粹的ANSI编译器。
写代码去完成这壹任务。
11.中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供壹种扩展—让标准C支持中断。
具体所代表的事实是,产生了壹个新的关键字__interrupt。
下面的代码就使用了__interrupt关键字去定义了壹个中断服务子程序(ISR),请评论壹下这段代码的。
__interruptdoublecompute_area(doubleradius)
{
doublearea=PI*radius*radius;
printf("Area=%f",area);
returnarea;
}
12.下面的代码输出是什么,为什么?
voidfoo(void)
{
unsignedinta=6;
intb=-20;
(a+b>6)puts(">6"):
puts("<=6");
}
13.评价下面的代码片断:
unsignedintzero=0;
unsignedintcompzero=0xFFFF;
/*1'scomplementofzero*/
不具备可移植性性
14.尽管不像非嵌入式计算机那么常见,嵌入式系统仍是有从堆(heap)中动态分配内存的过程的。
那么嵌入式系统中,动态分配内存可能发生的问题是什么?
char*ptr;
if((ptr=(char*)malloc(0))==NULL)
puts("Gotanullpointer");//1
else
puts("Gotavalidpointer");//2
输出2
这里,我期望应试者能提到内存碎片,碎片收集的问题,变量的持行时间等等。
这个主题已经于ESP杂志中被广泛地讨论过了(主要是P.J.Plauger,他的解释远远超过我这里能提到的任何解释),所有回过头见壹下这些杂志吧!
。
。
。
。
free
这是壹个有趣的问题。
最近于我的壹个同事不经意把0值传给了函数malloc,得到了壹个合法的指针之后,我才想到这个问题。
这就是上面的代码,该代码的输出是“Gotavalidpointer”。
我用这个来开始讨论这样的壹问题,见见被面试者是否想到库例程这样做是正确。
15.Typedef于C语言中频繁用以声明壹个已经存于的数据类型的同义字。
也能够用预处理器做类似的事。
例如,思考壹下下面的例子:
#definedPSstructs*
typedefstructs*tPS;
之上俩种情况的意图均是要定义dPS和tPS作为壹个指向结构s指针。
哪种方法更好呢?
(如果有的话)为什么?
16.C语言同意壹些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?
inta=5,b=7,c;
c=a+++b;
12
编程题
◆位操作练习
Description
假设你工作于壹个32位的机器上,你需要将某壹个外设寄存器的第X位设置成0(最低位为第0位,最高位为第31位),将第Y位开始的连续三位设置成110(从高位到低位的顺序),而其他位保持不变。
对给定的寄存器值R,及X,Y,编程计算更改后的寄存器值R。
Input
仅壹行,包括R,X,Y,以逗号","分隔,R为16进制表示的32位整数,X,Y于0-31之间且Y>=3,(Y-X)的绝对值>=3,保证俩次置位不会重合
Output
更改后的寄存器值R(16进制输出)
SampleInput
12345678,0,3
SampleOutput
1234567c
voidmain()
{
intR,X,Y;
scanf("%d,%d,%d",&R,&X,&Y);
R&=~(1<R|=6<<(Y-3);
R&=~(1<<(Y-2));
printf("theRvalueis%d",R);
}
◆排序
编写壹个排序程序。
被排序的文件有8MB大小,壹行壹个随机整数(ASCII格式)。
要求对这些整数进行排序,且计算平均值,打印出排序所需的时间。
#include"stdio.h"
#include"stdlib.h"
#include"math.h"
#include"time.h"
voidrun(int*pData,intleft,intright)
{
inti,j;
intmiddle,iTemp;
i=left;j=right;
middle=pData[left];
do{
while((pData[i]i++;
while((pData[j]>middle)&&(j>left))
j--;
if(i<=j)
{
iTemp=pData[i];
pData[i]=pData[j];
pData[j]=iTemp;
i++;
j--;
}
}while(i<=j);
if(leftrun(pData,left,j);
if(right>i)
run(pData,i,right);
}
voidQuickSort(int*pData,longCount)
{
run(pData,0,Count-1);
}
intmain(intargc,char*argv[])
{
clock_tstart,end;
//time_ta,b;
charfstr[20];
intm_data[1024];
longcount=0;
longsum=0;
longavr;
longi;
FILE*m_file;
if(NULL==argv[0])
{
exit
(1);
}
m_file=fopen(argv[0],"r");
if(m_file==NULL)
{
printf("error");
exit
(1);
}
while(NULL!
=fgets(fstr,20,m_file))
{
m_data[count]=atoi(fstr);
count++;
}
start=clock();
//a=time(NULL);
QuickSort(m_data,count);
end=clock();
printf("%6.3fseconds\n",(double)(end-start)/18.2);
//b=time(NULL);
for(i=0;i{
printf("\n%d",m_data[i]);
sum+=m_data[i];
}
avr=sum/count;
◆建立单向、双向、循环链表,进行相应操作
structNode{
intdata;//数据域
structNode*next;//指针域
};
单向:
structNode
{
intdata;
structNode*next;
};
structNode*Create_Node(intn)//CreateaNode,nmeansithasnchildnode;
{
structNode*p=(structNode*)malloc(sizeof(Node));//Createamemoryspaceforstruct
memset(p,NULL,sizeof(Node));//setthestruct’svalueNULL;
if(n>1)
{
p->next=Create_Node(n-1);//ifthenodehaschild,thenmakethep’snextlinkthenextnode
}
returnp;//returnthenode’saddress
}
voidDelete_Node(structNode*node)//freetheallnodetables
{
if(node->next!
=NULL)
{
Delete_Node(node->next);
}
node->next=NULL;
free(node);
}
双向:
structMuNode
{
intdata;
structMuNode*pre;//Pointertopointtopreviousnode
structMuNode*next;//Pointertopointtonextnode
};
structMuNode*Create_MuNode(intn,structMuNode*pre)
{
structMuNode*p=(structMuNode*)malloc(sizeof(Node));
memset(p,NULL,sizeof(Node));
p->pre=pre;
if(n>1)
{
p->next=Create_MuNode(n-1,p);
}
returnp;
}
voidDelete_MuNode(structMuNode*node)
{
if(node->next!
=NULL)
{
Delete_MuNode(node->next);
}
node->next=NULL;
node->pre=NULL;
free(node);
}
循环链表
structNode{
intdata;//数据域
structNode*next;//指针域
};
structNode*Create_CycleNode(intn,structNode*head)//CreateaNode,nmeansithasnchildnode;
{
structNode*p=(structNode*)malloc(sizeof(Node));//Createamemoryspaceforstruct
memset(p,NULL,sizeof(Node));//setthestruct’svalueNULL;
if(n>1)
{
p->next=Create_Node(n-1);//ifthenodehaschild,thenmakethep’snextlinkthenextnode
}
else
{
p->next=head;
}
returnp;//returnthenode’saddress
}
voidDelete_CycleNode(structNode*node,structNode*head)
{
if(node->next!
=head)
{
Delete_Node(node->next);
}
node->next=NULL;
free(node);
}
◆队列基本操作(入队,出队)
循环队列类型定义
#defineQueueSize100//应根据具体情况定义该值
typedefcharDataType;//DataType的类型依赖于具体的应用
typedefstruct{
intfront;//头指针,队非空时指向队头元素
intrear;//尾指针,队非空时指向队尾元素的下壹位置
intcount;//计数器,记录队中元素总数
DataTypedata[QueueSize];
}CirQueue;
voidInitQueue(CirQueue*Q)//初始化队列
{
Q->front=0;
Q->count=0;
Q->rear=0;
}
intQueueEmpty(CirQueue*Q)
{
return(Q->count==0)
}
intQueueFull(CirQueue*Q)
{
return(Q->count==QueueSize);
}
voidEnQueue(CirQueuq*Q,DataTypex)
{
if(!
QueueFull(CirQueue*Q))
{
Q->data[Q->rear]=x;
Q->rear=(Q->rear+1)%QueueSize;
Q->count++;
}
else
{
error("TheQueueisFull!
now!
\n");
}
}
DataTypeDeQueue(CirQueue*Q)
{
DataTypetemp;
if(QueueEmpty((Q))
Error("Queueunderflow")//队空下溢
temp=Q->data[Q->front];
Q->count--;//队列元素个数减1
Q->front=(Q->front+1)%QueueSize;//循环意义下的头指针加1
returntemp;
}
DataTypeQueueFront(CirQueue*Q)
{
if(!
QueueEmpty)
returnQ[Q->front];
else
{
error("Queueisempty");
}
}
◆栈基本操作(入栈,出栈)
#defineDataTypeint
#defineMAXSIZE1024
typedefstruct
{
DataTypedata[MAXSIZE];
inttop;
}SeqStack;
SeqStack*Init_SeqStack()//栈初始化
{
SeqStack*p=(SeqStack*)malloc(sizeof(SeqStack));
memset(p,NULL,sizeof(SeqStack));
returnp;
}
intEmpty_SeqStack(SeqStack*s)//判栈空
{
return(s->top==0);
}
intPush_SeqStack(SeqStack*s,DataTypex)//入栈
{
if(s->top{
s->data[s->top]=x;
return1
}
else
return0;
}
intPop_SeqStack(SeqStack*s,DataType*x)//出栈
{
if(s->top>0)
{
*x=s->data[s->top];
s->top--;
return1;
}
else
return0;
}
DataTypeTop_SeqStack(SeqStack*s)//取栈顶元素
{
if(s->top>0)
returns->data[s->top];
else
error("Stackisempty");
}
◆其他
编写壹个自己的完全C语言版本的memset函数,且且评价这个实现的性能和可移植性。
void*memset(void*source,intch,unsignedn);)
{
char*p=(char*)source;
assert(NULL!
=source);
while(n--)
{
*p++=(char)c;
}
returnsource;
}
◆代码风格
下面是壹个16x16的黑白图标:
staticunsignedshortstopwatch【】={
0x07c6,
0x1ff7,
0x383b,
0x600c,
0x600c,
0xc006,
0xc006,
0xdf06,
0xc106,
0xc106,
0x610c,
0x610c,
0x3838,
0x1ff0,
0x07c0,
0x0000,
};
如何修改声明,能够使之于源代码中形象地表现出图形的模样
//C编程专家
#defineX)*2+1
#define_)*2
#defines((((((((((((((((0
staticunsignedshortstopwatch[]=
{
s_____XXXXX___XX_,
s___XXXXXXXXX_XXX,
s__XXX_____XXX_XX,
s_XX________XXX__,
s_XX________XXX__,
sXX___________XX_,
sXX___________XX_,
sXX_XXXXX_____XX_,
sXX_____X_____XX_,
sXX_____X_____XX_,
s_XX____X____XX__,
s_XX____X____XX__,
s__XXX_____XXX___,
s___XXXXXXXXX____,
s_____XXXXX______,
s________________,
};
第三阶段Linux用户态开发
5天左右
熟悉Linux用户态开发的基本概念,通过编写壹些实验程序加深理解。
用户态编程学习内容
系统调用方式访问文件
库函数访问文件
时间编程
进程原理
进程控制程序设计
进程间通讯
管道
信号
共享内存
消息队列
信号量
多线程程序设计
socket编程(TCP,UDP)
Linux用户态编程实验内容:
编写应用程序,创建壹个可读可写的文件。
程序名:
CreateFile
#include
#include
#include
#include
#include
voidcreate_file(char*filename){
if(creat(filename,0755)<0){
printf("createfile%sfailure!
\n",filename);
exit(EXIT_FAILURE);
}else{
printf("createfile%ssuccess!
\n",filename);
}
}
intmain(intargc,char*argv[]){
inti;
if(argc<2){
perror("youhaven'tinputthefilename,pleasetryagain!
\n");
exit(EXIT_FAILURE);
}
for(i=1;icreate_file(argv[i]);
}
exit(EXIT_SUCCESS);
}
执行命令:
gccCreateFile–oCreateFile
./CreateFile
使用库函数,实现文件拷贝的功能
获取本地时间,以字符串方式显示
编写壹应用程序,于程序中创建壹子进程,分别于父进程和子进程中打印进程ID
使用vfork创建壹子进程,分别于父进程和子进程中打印进程ID,观察父子进程的运行顺序
使用execl函数创建壹个文件
编写壹应用程序,于程序中创建壹子进程,父进程需等待子进程运行结束后才能执行
于父进程中创建壹个无名管道,且创建子进程来读该管道,父进程来写该管道
启动A进程,创建壹有名管道,且向其写入壹些数据;启动B进程,从A创建的有名管道中读出数据
于进程中为SIGBUS注册处理函数,且向该进程发送SIGBUS信号
启动A进程,创建壹共享内存,且向其写入壹些数据;启动B进程,从A创建的共享内存中读出数据
创建壹消息队列,实现向队列中存放数据和读取数据
编写应用程序,创建壹线程,且向该线程处理函数传递壹结构
编写应用程序,创建壹线程,父进程需要等待该线程结束后才能继续执行
编写应用程序,创建壹线程,使用pthread_cl