Linux操作系统-第6讲C语言编程_第1页
Linux操作系统-第6讲C语言编程_第2页
Linux操作系统-第6讲C语言编程_第3页
Linux操作系统-第6讲C语言编程_第4页
Linux操作系统-第6讲C语言编程_第5页
已阅读5页,还剩37页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第6讲 C语言编程 gcc、gdb的使用与Linux进程创建Linux的程序文件名后缀后缀后缀文件类型文件类型.cC语言源代码文件.c或.cc或.cxx C+源代码文件.s汇编语言源代码文件.h头文件.i已预处理过的C语言源代码文件.ii已预处理过的C+语言源代码文件.S已预处理过的汇编语言源代码文件.o编译后的目标文件.so目标文件构成的动态库文件.a目标文件构成的静态库文件GCC编译器 GCC是GNU C Comiler的缩写,是GNU推出的 完全免费、功能强大,支持多种语言(C,C+,FORTRAN,PASCAL,ADA)的编译器。 支持多种硬件平台,执行效率快多种硬件平台,执行效率快,

2、比一般的编译器的执行效率高20%30% 。 查看gcc版本:gcc -vGCC编译过程 预处理预处理:调用linux的CPP预编译程序,生成.i的临时文件。 将#include 文件拷贝到要编译的源文件中。 用实际值替代#define文本。 在调用宏的地方进行宏替换。命令#gcc E o test.i test.c或#cpp test.ctest.i 汇编汇编:调用linux的as汇编编译程序,生成.s的汇编文件。命令#gcc S test.c 编译编译:调用linux的cc1编译程序,生成.o的目标文件。命令#gcc c test.c 链接链接:调用linux的ld链接程序,生成最后的可执行

3、文件。命令#gcc o test test.c 执行执行#./testGcc的基本选项 Gcc options filenames Options有如下常用选项: -S:对源程序进行预处理和编译,不进行汇编和链接,自动生成汇编文件。 -c:执行预处理、编译、汇编而不链接,生成.o为后缀的目标文件。通常用于编译没有主程序的子程序文件。 -o output_filename:指定输出文件名为output_filename,不指定时缺省文件名为a.out -g:产生调试信息。 -x:指定待编译程序的语言。如gcc xc+ test.cpp -O0:不优化。 -O1:第一级优化。允许与-g共用,编译链

4、接过程稍慢。 -O2:第二级优化。特别对于大型程序,可以大幅度提高运行速度。 -O3:第三级优化。与O2的区别在于它允许把函数直接插入到调用的代码处 。Gcc函数库 Gcc options 选项: -lm 指定函数库 -L 指定函数库的搜寻目录 -I指定include 所在目录。 Gcc函数库 共享函数库的格式fun.so.x.x.x,其中x.x.x指版本号,共享函数库通常会有符号链接指向静态函数库或相关so的文件。 命令ldd用于查出程序所用的共享函数库。 例1: ldd test 例2: ldd sin分别编译main()和其他函数程序维护工具make Linux 系统的许多软件都是使用m

5、ake程序和 makefile来维护而实现自动编译的, make程序自动确定需要重新编译的文件,只对他们进行重新编译,然后链接生成可执行文件。 make程序是在程序调试、改进过程中必不可少的工具。 make程序可以自动对已修改的源程序进行编译,而对未改变的部分则跳过编译步骤,从而大大提高效率,是源程序的编译、链接、管理更加规范和有条理。 make程序需要两方面的信息:一是可执行文件和各个程序模块之间的关系,二是文件的修改日期。 可执行文件和各个程序模块之间的关系通常记录在makefile或Makefile中。makefile语法target(目标名):dependency(依赖模块)comma

6、nd(命令行) 依赖关系一行放不下时,续行用“”标记。 命令行command之前不可有空格,只是加制表符tab 命令行command行中的命令若不想显示在屏幕上则在其前加 例如makefile文件为test : testmain.o testfun.ogcc -o test testmain.o testfun.otestmain.o : testmain.cgcc -c testmain.ctestfun.o: testfun.cgcc -c testfun.cclean:rm f test*.o写makefile. 注意:命令前用键GDB调试器 GDB是GNU自带的调试工具,GDB支持C,

7、C+,Modula-2等。 编译程序时加调试开关 #gcc g -o test test.c 进入调试状态# gdb test GDB常用命令命令名命令名参数参数说明说明break行号、函数名、地址设置断点。clear行号、函数名、地址去掉指定位置的断点,未指定位置则去掉当前断点。run命令 参数开始运行被调试程序。continue继续程序运行,直到下一个断点或程序结束list-、行号、函数名、地址显示指定行的源代码,-表示前10行,否则回10行。next数值单步运行,不进入函数体。step数值单步运行,进入函数体。disp表达式显示表达式的值。print表达式临时显示表达式的值,下次运行时表

8、达式的值不显示。call函数程序执行中调用指定函数。finish继续程序运行,直到下一个断点或返回调用者。file文件名打开要调试的文件。quit退出GDB。GDB其他使用技巧 在GDB下执行shell命令( gdb)shell commandline 重复上次命令的执行直接回车 指令级的调试 stepi/nexti(指令级单步执行) disp/x $寄存器(显示寄存器的值) 出错后的调试。程序发生错误时,会在当前目录下产生一个名为core的内存映像文件。 #gdb a.out core 获得帮助 Shell状态下,运行info gdb 或 man gdb GDB状态下,运行(gdb)help

9、或(gdb)help GDB命令名Linux中的进程 进程这个概念是伴随着Unix的产生而出现的,Unix之父Dennis Ritchie当初用来发表Unix的论文的时候就提出了用进程的观点来看待整个操作系统,随着操作系统理论的发展,进程作为程序执行的实体和资源分配的单位的观念也在变化。线程的出现,改变了进程的传统概念。但是在linux中,进程仍然保留着传统的意义,它包括四个要素: 程序段。 系统堆栈空间。 task_struct结构(PCB)。 专有内存空间。Linux中的线程单进程单线程单进程多线程多进程每个进程一个线程多进程每个进程多个线程linux的线程模型是一种一对一模型,也就是每个

10、线程实际上在核心是一个单独的进程,核心的调度程序负责线程的调度。进程控制块和堆栈 作为描述进程信息,操作系统感知进程存在的进程控制块(PCB),在linux中是由结构task_struct来实现的。t a s k _ s t r u c t 的 定 义 在include/linux/sched.h中给出。 当产生一个的进程时,在内核空间中会分配一个8K的空间来记录新进程的信息,其中包括task_struct结构和为进程分配的内核堆栈,当进程由于系统调用转到内核时,就要切换到该进程的内核堆栈了。 task_struct结构可以被系统中的许多模块访问,如调度程序、资源分配程序、中断处 理 程 序

11、等 。 由 于task_struct结构经常被访问,它常驻内存。 task_struct系统空间堆栈(大约7KB)两个连续物理页面(8KB)linux进程的创建与执行 linux进程创建创建用以下系统调用完成: 系统调用fork():父进程的所有资源通过数据结构复制全部给子进程。 fork()用于创建进程。用于创建进程。 后增设的系统调用vfork(): 除了task_struct和系统空间堆栈以外的资源全部都通过数据结构指针的复制“遗传”。所以vfork创建的是线程,而创建的是线程,而不是进程。不是进程。 系统调用clone():进程的资源有选择地复制给子进程,而没有复制的数据结构(资源如内

12、存空间)通过指针的复制让子进程共享。 用clone既可以既可以创建创建一个进程,也可以创建一个进程,也可以创建一个线程。一个线程。创建子进程后父进程的选择 创建子进程后,父进程可以有以下几种选择: 父进程不受影响,继续执行,也称“异步”方式。 父进程停下来,等待子进程完成后,再继续执行,也称“同步”方式。用系统调用wait()和 waitpid()实现。 wait()是等待所有子进程完成; waitpid()等待特定子进程完成。 父进程创建了子进程后,马上结束自己。用系统调用exit()实现。进程的撤消 用户程序中好像没有调用exit()就结束了,实际上当用户程序编译时,编译器在程序的结尾处加

13、上一个exit()系统调用的,所以当进程完成任务时,就会调用exit()来结束自己。用户程序也可以主动地调用exit()来显式的结束。 fork() #include #include pid_t fork(void); fork()函数是一个单调用双返回函数。调用后,子进程是父进程的一个复制,父子进程都从fork()语句的一条语句开始执行。 调用正确完成时, 给父进程返回的是被创建子进程的进程标识符(给父进程返回的是被创建子进程的进程标识符(0)。)。 给子进程返回的是给子进程返回的是0。 调用失败时给父进程返回调用失败时给父进程返回-1。fork()使用举例/fork .#include

14、#include #include int glob = 3;int main(void) pid_t pid; int loc = 3; printf(Before fork :glob=%d,loc=%dn,glob,loc); pid = fork(); if (pid 0) printf(fork errorn); exit(0); else if (pid = 0) glob = glob + 1; loc= loc - 1;/sleep(1); printf(Now child process changes glob=%d and loc=%dn,glob,loc); else

15、printf(parent process doesnt changes the glob=%d and loc=%d n,glob,loc); printf(End pid=%d,:glob=%d,loc=%dn,pid,glob,loc); exit(0);fork()运行结果分析 fork()可能产生两种运行结果: 一种为:子进程先运行,父进程后运行 另一种为:父进程先运行,子进程后运行vfork()使用举例/vfork .#include #include #include int glob = 3;int main(void) pid_t pid; int loc = 3; prin

16、tf(Before vfork :glob=%d,loc=%dn,glob,loc); pid = vfork(); if (pid 0) printf(vfork errorn); exit(0); else if (pid = 0) glob = glob + 1; loc= loc - 1;sleep(1); printf(child process changes glob=%d and loc=%dn,glob,loc); exit(0); else printf(parent process doesnt changes the glob=%d and loc=%d n,glob,

17、loc); printf(End:glob=%d,loc=%dn,glob,loc); exit(0);vfork()运行结果分析 vfork()可能产生两种运行方式,但变量最后结果是一样的(因为是指针复制):clone()#include #include int clone(int(*fn)(void*),void *child_stack, int flags,void *arg); 与fork()不同的是,clone()函数创建的线程或进程,另立门户。 当线程被创建后,执行fn(arg) 指定的函数。 fn是指向执行函数的指针,arg是传递给含数的参数。当 fn(arg) 执行终止时,

18、线程撤消。 fn返回的是整型值,即线程的退出码。线程也可以调用exit()终止自己。child_stack说明线程使用的堆栈,它是指向堆栈的指针。 当线程终止时,用flags的低字节给父进程返回信号, 调用正确完成时,与fork()一样,给父进程返回的是被创建线程的标识符。 调用失败时给父进程返回-1。 clone()函数是Linux专用的。clone()使用举例#include #include int myfun() printf(Now in thread!n); exit(0);int main() int fd; void *child_stack; int flag; typede

19、f int (*fn)(void *); void *arg; int p20; child_stack = p; fd = clone(fn)myfun,child_stack,flag, arg); if (fd 0) printf(Thread created!fd=%dn,fd); else printf(Thread create Failn); sleep(1); exit(0);clone()运行结果分析 clone()是Linux专用的,不能在其他类unix系统上使用。用clone传递参数#include #include int myfun(int *argfun) int

20、x,y; printf(Now in threadn); x = *argfun; argfun = argfun + 1; y = *argfun; if (xy) printf(max=%dn,x); else printf(max=%dn,y); /exit(0);int main() int fd; void *child_stack; int flag; typedef int (*fn)(void *); void *arg; int p20; int a2; a0 = 6; a1 = 5; child_stack = p; arg = a; fd = clone(fn)myfun

21、(arg),child_stack,flag, arg); if (fd 0) printf(Thread created!fd=%dn,fd); else printf(Thread create Failn); exit(0);父子进程同步wait #include #include pid_t wait(int *status);/等待所有子进程完成 pid_t waitpid(pid_t pid, int *status, int options);/等待特定子进程完成。wait使用举例/forkwait#include #include #include int main(void)

22、 pid_t pid; pid = fork(); if (pid 0) printf(fork errorn); exit(0); else if (pid = 0) printf(Now child processn); sleep(1); exit(0); wait(); printf(End parent now!n ); exit(0);将wait()可以改为waitpid(pid),效果相同运行结果分析 运行结果只有一个,子进程先执行,子进程结束后父进程再执行。kill( )函数 kill()函数用于删除执行中的程序或者任务。 调用格式:调用格式: kill(int PID,int

23、 IID); 其中:PID是要被杀死的进程号,IID为向将被杀死的进程发送的中断号。 signal()函数signal())函数 signal()函数是允许调用进程控制软中断信号的处理。 调用格式:调用格式: #include int sig; void func(); signal(sig,func); sig的值是下列之一:SIGHUP 挂起 1 SIGINT 键盘按delete键或break键 2 SIGQUIT 键盘按quit键 3 SIGILL 非法指令 4 SIGTRAP 跟踪中断 5 SIGIOT IOT指令 6 SIGBUS 总线错 7 SIGFPE 浮点运算溢出 8 SIGK

24、LL 要求终止进程 9 SIGUSR1 用户定义信号#1 10 SIGSEGV 段违法 11 SIGUSR2 用户定义信号#2 12 SIGPIPE 向无读者管道上写 13 SIGALRM 定时器告警,时间到 14 SIGTERM kill发出的软件结束信号 15 SIGCHLD 子进程死 17 SIGPWR 电源故障 30function的解释如下Function:在该进程中的一个函数地址,在核心返回用户态时,它以软件中断信号的序号作为参数调用该函数,对除了信号SIGILL、SIGTRAP和SIGPWR以外的信号,核心自动地重新设置软中断信号处理程序的值为SIG_DFL,一个进程不能捕获SI

25、GKILL信号。实现软中断通信的程序 使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按Del键),当父进程接受到这两个软中断的其中某一个后,父进程用系统调用kill()向两个子进程分别发送整数值为16和17软中断信号,子进程获得对应软中断信号后,分别输出下列信息后终止: Child process 1 is killed by parent ! Child process 2 is killed by parent ! 父进程调用wait()函数等待两个子进程终止后,输出以下信息后终止: Parent process is killed! 软中断流程图 开开始始初初始始化化软软中中断断信信号号集集创创建建子子进进程程1 1子子进进程程1 1创创建建成成功功?否否是是是是否否子子进进程程1 1等等待待软软中中断断信信号号1 16 6发发生生否否等等待待软软中中断断发发生生是是是是过过了了5 5秒秒?否否产产生生软软中中断断S SI IG GA AL LR RM M是是调调用用k ki il ll l( ( ) )向向两两子子进进程程发发中中断断信信号号等等待待子子进进程程1 1终终止止结结束束子子进进程程2 2等等待待软软中中断断信信号号1 17

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论