张浩宇,吕成国,高扬
(黑龙江大学,黑龙江 哈尔滨 150080)
随着后PC(Post- Personal Computer)时代的到来,原有的参照ACM(Association For Computing Machinery,国际计算机学会)和IEEE(Institute of Electrical and Electnaics Engineers,电子和电子工程协会)制定的计算机专业、软件工程专业课程体系已经不能满足现阶段人才培养要求,其主要表现为:原课程体系设置了很多门独立的课程,课程之间缺乏关联和系统性,学生在学习过程中难以系统性地理解整个计算机系统的工作原理和方法,导致学生缺乏系统思维,因此亟需一门独立的能够贯穿整个计算机系统的基础课程,培养学生系统思维能力,使人才培养目标由程序设计逐步变为系统设计。
基于以上原因,为了推动软件工程专业课程的教学改革,利用2019 版人才培养方案的修订契机,黑龙江大学软件学院决定在软件工程专业培养计划中增设一门专业必修课程“计算机系统基础”,该课程力求从程序员视角出发,重点介绍应用程序员如何利用计算机系统相关知识来编写更有效的程序。以高级语言程序的开发和运行过程为主线,将该过程中每个环节所涉及的硬件和软件基本概念关联起来,使学生建立一个完整的计算机系统层次结构框架,了解计算机系统的全貌和相关知识体系,初步理解计算机系统中的每一个抽象层及其相互转换关系,增强学生在程序的调试、性能优化、移植和健壮性保证等方面的能力。
目前,国内讲授“计算机系统基础”课程最为权威的是南京大学袁春风教授的教学团队,该团队出版了教材《计算机系统基础》,该书以IA-32 架构和linux 操作系统为平台,用真实的应用实例介绍在编写程序过程中出现的各种错误,分析出现这些错误的原因,并指出解决这些错误的方法[1]。袁教授的教学团队编写了与教材配套的《习题解答和教学指导》,并在中国大学MOOC 平台上发布了完整的慕课资源供学生学习。笔者基于袁教授教学团队“计算机系统基础”课程教学模式,对照黑龙江大学计算机科学技术学院的学生培养计划在理论课程体系、实验课程体系、考核方式三个方面进行建设。
关于理论课程体系的建设,课程组从教材选用、教学内容重组、教学内容增加三个方面进行了课程建设。
如前所述,袁春风教授的教学团队将“计算机系统基础”课程建设得非常完备,是“计算机系统基础”课程建设的学习楷模,因此课程组决定选用袁教授编写的最新教材——《计算机系统基础(第2 版)》作为我们的教材。这本教材全书共8 个章节,分别是计算机系统概述、数据的机器级表示与处理、程序的转换及机器级表示、程序的链接、程序的执行、层次结构存储系统、异常控制流、I/O 操作的实现。袁春风教授在前言中建议软件工程专业讲授这门课程不仅要把全书的章节8 个内容全部讲授,还要将附录中的数字逻辑电路基础也进行讲授,这样本课程需要分为两个学期讲授,每学期的总学时为60 学时左右。而黑龙江大学计算机科学技术学院制定的教学计划是理论课讲授48 学时,实验课16学时,总学时64 学时,在这门课前开设一门总学时为34 学时的“数字逻辑”课程,以便为该课程奠定硬件知识基础。考虑到课时设置的不同,课程组重新制定了教学计划,以教材的第一、二、三章的内容作为讲授的重点,第四、五、六章的内容略讲,第七、八章的内容不作为考核内容,只作为学生自学内容。在讲授教材前三章的内容时,如果涉及到第四、五、六章的知识点就把它们穿插进前三章的授课内容中,以求给学生展示一个相对完整的计算机系统。
“计算机系统基础”课程是一门软硬件系统兼顾,以培养学生系统思维、系统设计能力为目的的课程。在讲授过程中必然要涉及许多硬件系统的知识,这些知识很多是“数字逻辑”课程上没有讲授而本课程又必须使用的。鉴于此,课程组就需要考虑教材第一章讲授内容的顺序以及与教材后续内容的重组问题。
教材第一章的讲授内容主要围绕以下四个方面进行:计算机基本工作原理、程序的开发与运行、计算机系统的层次结构、计算机系统性能评价。在具体讲授的过程中,考虑到学生已经学习了“程序设计基础”和“数字逻辑”两门课,本着循序渐进、先软件后硬件的原则,课程组调整了本章的讲授顺序,首先讲授计算机系统的层次结构,然后讲授程序的开发与运行,再讲授计算机基本工作原理,最后讲授计算机系统性能评价。在讲授计算机系统的层次结构部分时,让学生初步对计算机系统有一个完整的系统概念,厘清计算机软件子系统和硬件子系统之间的关系,明确软件子系统和硬件子系统在功能上具有等效性。在讲授程序的开发与运行部分时,需要将第四章的编译、汇编和静态链接,目标文件这些知识融合进来,让学生清晰地看到一个程序是如何从文本文件转换成目标文件并在计算机中被执行的全部过程,以充分理解软件子系统的功能。在讲授计算机基本工作原理的部分时,将第五章的程序的执行过程、数据通路的知识,第六章主存与CPU 的连接及其读写操作的知识融合进来,让学生深刻体会目标文件在存储器中是如何存放的,又如何被CPU 读取执行的,在此过程中CPU 与存储器之间是如何配合工作的等一系列与计算机硬件子系统息息相关的操作过程。通过一个简单程序做例子,把以上三个部分有机地联系在一起,让学生清楚地感受到软件子系统和硬件子系统互相配合工作,形成了一个完整的计算机系统,达到了初步培养学生系统思维的目的。
教材第三章的讲授内容主要围绕以下六个方面进行:程序转换概述、IA-32 指令系统概述、IA-32 常用指令类型及其操作、C 语言程序的机器级表示、复杂数据类型的分配和访问、越界访问和缓冲区溢出。其中前三部分知识是本章知识讲授的基础,由于学生之前没有接触过IA-32 汇编语言,如果完全按教材讲授,学生对这三个部分知识体系学习不充分,会直接影响对后续三个部分知识的学习理解,因此课程组还要增加有关IA-32 汇编语言程序设计的内容。
课程组增加的有关IA-32 汇编语言程序设计的内容共有六部分:80X86 的寄存器、AT&T 汇编语言的格式、IA-32 汇编的寻址方式、IA-32 汇编指令系统、简单汇编语言程序举例与伪操作、带子程序的汇编语言程序举例。其中80X86 的寄存器、IA-32 汇编的寻址方式、IA-32 汇编指令系统三个部分教材中有介绍但不完整,课程组需要将其补充完整;AT&T 汇编语言的格式、简单汇编语言程序举例与伪操作、带子程序的汇编语言程序举例三个部分是根据后续学习需要增加的全新部分。通过讲授相对完整的IA-32 汇编语言程序设计的知识,使学生可以读懂并编写IA-32 汇编语言程序,在学习过程中,可以让学生利用C 语言与IA-32 汇编语言编写相同功能的程序代码,利用C 语言程序与IA-32 汇编语言程序的对比,加深学生对C 语言程序的机器级表示的理解,尤其是学习了带子程序的汇编语言程序举例部分的知识,可以促进学生对堆栈操作和内存存储的理解,能够使学生更好地掌握复杂数据类型的分配和访问、越界访问和缓冲区溢出这两部分讲授的知识。
关于实验课程体系的建设,课程组从实验的设置、与教学内容相关实验的目标、扩展实验内容的目标三个方面进行了实验课程体系的建设。
虽然袁春风教授的团队有完整的教学资源,但是实验教学环节与黑龙江大学计算机科学技术学院的实际教学情况不相匹配。袁教授团队设计的实验分小实验和大实验两部分,小实验主要是对理论课程讲授的知识进行验证性实验,而大实验主要是根据理论课程讲授的知识进行综合性、扩展性实践。对于学生来说,小实验的难度过于简单,大实验的难度又过难,使得课程组不能照搬现成的实验项目,只能根据学生的具体情况自己设计难度适中的实验。
课程组设计了8 个实验,分别是:Linux 环境下C语言开发实验,十进制数与二进制数、原码、反码、补码互换实验,十进制数与IEEE754 标准浮点数互换实验,linux 环境下汇编语言开发实验,汇编语言四则运算实验;汇编语言子程序实验,二进制炸弹实验,Linux 进程管理、共享内存、多线程实验。其中前6 个实验是与教材直接相关的实验,设置目的是通过实践编程加深对理论知识的理解;后两个实验属于综合性扩展实验,设置目的是提高学生综合应用能力,培养系统思维能力,为后续课程的学习奠定基础。
实验一是培养学生在Linux 环境下使用GCC 编译C 语言程序、使用GDB 调试C 语言程序和使用Make工具实现多个C 语言程序模块化编译一个工程的能力。《计算机系统基础》这本教材中的例题几乎都是在Linux 环境下进行分析,学生为了能重现教材中的例题就必须学会在Linux 环境下的C 语言程序设计方法,熟练掌握在Linux 环境下的C 语言程序的编译、调试方法,以及多个C 语言程序利用Make 工具实现模块化编译的方法,基于此设置了实验一。实验二要求学生通过C 语言编写二进制数与十进制数互相转换程序,带符号二进制数与原码、反码、补码互相转换程序。在理论教学过程中,我们已经讲授了这些转换的方法,但是我们要通过实验加深学生对这些转换方法的理解,引导学生思考在计算机中如何通过软件编程实现这些方法,同时在编写程序的过程中加强学生对程序模块化设计的训练。实验三要求学生通过C 语言编写十进制数与IEEE754 标准浮点数的互相转换程序。通过实验加深学生对IEEE754 标准浮点数表示中阶码、隐藏位等知识的理解,明确十进制数据如何与IEEE754 标准的浮点数进行互换。以上三个实验与第二章的理论内容相关联,通过C 语言编程实现相关理论内容,使理论与实践更紧密地结合。
实验四是培养学生在Linux 环境下使用AS 和LD编译汇编语言程序、使用GDB 调试汇编语言程序的能力。由于理论教学部分在第三章增加了有关IA-32 汇编语言程序设计的知识,掌握IA-32 汇编语言程序的编译、调试方法是必不可少的。实验五要求学生用IA-32 汇编语言编写四则混合运算程序、在无序数组中查找最大数程序。通过这个实验让学生亲手编写具有顺序、分支和循环结构的IA-32 汇编语言程序,对比相同功能的C 语言程序,感受二者的相同点与不同点,进而体会C 语言程序的机器级表示,培养学生的汇编语言程序设计能力。实验六要求学生编写一个带子程序的IA-32 汇编语言程序,求一个数组中所有数据的平方之和,求平方的过程必须使用子程序完成。通过这个实验让学生体会带子程序的IA-32 汇编语言程序在主程序与子程序进行切换时系统堆栈段的变化,主程序与子程序之间参数的传递过程,进而促进学生对C 语言子函数中参数的作用域和生存周期的理解。以上三个实验与第三章的理论内容相关联,通过编写IA-32汇编语言程序,加深学生对C 语言程序的机器级表示的理解,使学生能够写出更加优化健壮的C 语言程序代码,同时对编译原理有一个初步的认识。
实验七是袁老师慕课团队设计的一个实验,该实验要求运用第二章和第三章所学知识,拆除一个二进制炸弹程序中设置的多个关卡,在该过程中增强对程序与数据的机器级表示、汇编语言、调试器和逆向工程等方面知识与技能的掌握。二进制炸弹是一个Linux 可执行程序,包含了多个阶段。在炸弹程序运行的每个阶段要求输入一个特定字符串,如果该输入字符串符合程序的要求,该阶段的炸弹就被拆除了,否则炸弹“爆炸”,即打印输出“BOOM!!!”的提示。这个实验考察学生对字符串比较、浮点数表示、C 语言循环机器级表示、C语言条件分支机器级表示、递归调用和栈的操作、指针的分配与访问、链表与结构的分配与访问七个方面的理解,系统地对本课程中第二章、第三章的教学重点进行了一次综合考察,加深了学生对汇编语言程序设计的理解,同时也使学生对逆向工程有一个初步的了解。这个实验难度略高,给学生一个挑战自我的机会。
实验八是一个扩展实验,目的是使学生初步了解进程的概念、进程通信和多线程的执行三个方面的知识。实验的内容有三个:第一,利用fork 和execl 族函数,实现进程的创建,并在进程中运行新代码;第二,实现两个进程间通过共享内存进行数据通信;第三,实现多个线程并行执行。考虑到这些内容属于学生自学内容,实验要求学生完成这三个程序的任意一个即可。这部分知识不在课堂讲授范围以内,但是在后续操作系统课程学习中一定会涉及到这些知识,为了能让学生尽快在头脑中形成操作系统课程的学习体系,在这里通过实验的形式,要学生先行学习一些基础知识。
为了提高学生学习主动性,课程组决定适当增加过程考核比重,过程考核占总成绩的50%,期末试卷考核占总成绩的50%。过程考核分为两大部分:作业与测试成绩、实验成绩。作业与测试成绩占总成绩的20%,其中作业成绩占总成绩10%,测试成绩占总成绩10%。作业由教师在学校的自主学习平台发布,每次作业满分为10 分,全部作业总分折合成10 分。测试部分以教材的前两章内容为考核范围,采用课堂随堂测试的方式,在学校的自主学校平台发布测试题目,满分100分,在规定时间内完成,折合成10 分。实验成绩占总成绩的30%,采用每个实验按满分10 分的标准对实验程序的完整性、正确性以及学生完成实验的速度进行综合评测,然后将八个实验的总成绩折合成30 分。
经过在理论课程体系、实验课程体系、考核方式三个方面的建设,初步形成了较为完整的“计算机系统基础”课程教学体系。经过两轮课程讲授取得了良好的效果,2019 级和2020 级软件工程专业学生的期末成绩及格率在90%以上,通过该课程的学习,给学生建立了计算机系统的整体概念,培养了学生的系统思维系统设计的能力,激发了学生自主学习的兴趣,为后续操作系统课程打下了坚实的基础。
“计算机系统基础”是一门全新的课程,对课程组全体教师也是一项全新的挑战。虽然本课程组教师有多年的主讲“计算机组成原理”“80X86 汇编语言程序设计”课程的经验,但他们缺少“程序设计基础”和“操作系统”课程的主讲经验,课程的衔接方面有些不足,这需要教师进一步完善课程体系,补足短板。课程组下一步计划根据学院教学特点编写一本更加切合课程体系的教材,力求早日形成课程的无缝衔接。