本文在中科大软件学院孟宁老师的指导下完成,意在经过对小型程序的分析来帮助体会软件工程方法、思想。git
本文的参考资料及资源来自:软件工程——码农的自我修养。程序员
有关VS Code的安装配置能够参考该资料:https://mp.weixin.qq.com/s/sU9Wh12JZqQyJfEBBafFAQshell
在本文中,咱们对此进行简单介绍。咱们能够在VS Code官网下载,它是一款免费的轻量级IDE,经过扩展插件能够支持多种语言。编程
下载地址:https://code.visualstudio.com/#alt-downloadsjson
在VS Code中,当咱们经过加载扩展插件来实现支持时,它并不会包含语言的编译器与调试器。这里所说的编译器与调试器,对于C++而言,即为MinGw。安全
C/C++编译器则为MinGw: http://www.mingw.org/数据结构
下载完成并安装后,咱们能够获得如下目录:并发
一般状况下,在安装MinGw时,会建议或者要求咱们将其添加到环境变量中。但若是咱们忘记了配置,也能够经过如下方法手动进行配置。模块化
首先,咱们须要获取到MinGw在咱们系统中的安装位置,如上所示,即为:C:\MinGw 。函数
以后,右键点击此电脑 -> 选择属性 -> 高级系统设置 -> 环境变量,在此处能够管理咱们计算机的环境变量。咱们找到下方系统变量中的Path选项:
经过编辑Path选项,新建添加新环境变量地址,填入上述安装位置。须要注意的是,咱们此时需填入C:\MinGw\bin。
以上即为C/C++编译器的环境安装配置过程。对于其余语言,如Java、Python、Golang,咱们都可以采用此种方法。
咱们能够经过命令提示符查看MinGw的安装是否成功,使用gcc -v指令:
在VS Code左侧扩展选项中,咱们搜索C++便可搜索到插件,点击Install后便可安装完成:
VS Code经过 task.json 配置文件来获取编译程序的方式,经过修改task.json就能够利用VS Code进行gcc编译源码了。
一个参考的task.json文件配置以下:
{ "version": "2.0.0", "tasks": [ { "type": "shell", "label": "gcc build active file", "command": "gcc", "args": [ "-g", "${file}", "-o", "${fileDirname}/${fileBasenameNoExtension}"// ], "group": { "kind": "build", "isDefault": true } } ] }
关于task.json的格式,能够参考如下文档:https://go.microsoft.com/fwlink/?LinkId=733558
VS Code经过launch.json配置文件中的配置来调用调试器对程序进行调试。经过快捷键Ctrl+Shift+P,搜索launch.json,能够打开launch.json进行配置。
一个参考的launch.json的配置文件以下:
{ "version": "0.2.0", "configurations": [ { "name": "gcc build and debug active file", "type": "cppdbg", "request": "launch", "program": "${fileDirname}/${fileBasenameNoExtension}", "args": [], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": false, "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ], "preLaunchTask": "gcc build active file", "miDebuggerPath": "C:\\MinGW\\bin\\gdb.exe" // 此处为上述的MinGw安装地址 } ] }
关于launch.json文件的配置,能够参考如下文档:https://go.microsoft.com/fwlink/?linkid=830387
能够看到,运行如下示例成功,说明环境配置成功!
良好的注释风格,能够帮助代码阅读者、维护者等人员快速明确地了解到代码所实现的功能等,方便Debug。一个优秀的代码注释风格以下,这是孟宁老师所给出的案例,很是值得学习:
从中,能够清楚地看到,这个文件中的代码的文件名、做者、模块名、语言类型、运行环境、版本时间以及描述等,对咱们理解代码十分有帮助。
模块化(Modularity)是指,在指软件系统设计时保持系统内各部分相对独立,以便每个部分能够被独立地进行设计和开发。这样使得咱们在开发过程当中,每个模块都执行本身单一的功能目标,能够独立于其余软件模块,这样也就方便了开发人员之间的配合。
模块化的基本原理是关注点的分离(Soc,Separation of Concerns),翻译成中文其实大概即是“分而治之”。
在实际的软件设计开发中,咱们通常使用耦合度(Coupling)和内聚度(Cohesion)来做为软件模块化程度的高低,它们一样是判断一个软件设计优良程度的重要参考。
耦合度,是指一个软件中各个模块之间的依赖程度,从高到低在大体上能够分为紧密耦合(Tightly Coupled)、松散耦合(Loosely Coupled)。咱们所追求的是松散耦合,它代表咱们所设计的软件各个模块的依赖程度较低,是比较好的设计。
内聚度,是指一个软件模块内部各类元素之间互相依赖的程度。理想的内聚是功能内聚,也即一个模块只作一件事,只完成一个主要功能。
在实现模块化设计时,咱们能够将多种数据封装成结构体、将实现功能封装成一个文件,能够帮助咱们简化代码:
在上图中,咱们将数据结构以及函数声明放在一个linklist.h的头文件中,其实现放在linklist.c文件,须要调用时再在main函数中去调用,这样就实现了较低的耦合度,也方便咱们做为程序员去debug。
接口是通讯双方共同遵照的一种规范,在软件系统内部通常的接口方式是经过一组API函数来约定软件模块之间的沟通方式。面向对象与面向过程的语言在对接口的是实现通常不相同。前者的接口是对象对外开放的一组属性和方法的集合;后者则是数据结构和操做这些数据结构的函数等。
上图借用了孟宁老师提供的工程源码文件中的某个源码文件。在这个文件中,能够看到其声明了许多接口,这些接口的实现会放在.c文件中。但不经过具体的实现代码,咱们依然能够经过接口的名称、参数、返回值以及相关描述了解到大概的功能,这些接口的也能够被屡次重复使用,提升了代码的复用性。
线程(thread)是操做系统可以进行运算调度的最小单位。它包含在进程之中,是进程中的实际运做单位。一个线程指的是进程中一个单一顺序的控制流,一个进程中能够并发多个线程,每条线程并行执行不一样的任务。
线程安全问题都是由全局变量及静态变量引发的。若每一个线程中对全局变量、静态变量只有读操做,而无写操做,通常来讲,这个全局变量是线程安全的;如有多个线程同时执行读写操做,通常都须要考虑线程同步,不然就可能影响线程安全。
可重入(reentrant)函数能够被多个线程并发执行,而一般不会致使因为共享数据而致使结果错误;不可重入函数则在多个线程并发执行时,若是不能保持线程互斥,那么就会致使结果的错误。对于软件工程而言,咱们应该以比较悲观的方式去评估函数:便可重入函数不必定是线程安全的,多是线程安全的函数就不是线程安全的函数,不可重入函数必定不是线程安全的函数。
首先,对于线程安全,咱们所关注的焦点通常在如下几个方面:
i. 全部的函数是否是都是可重入函数:分析函数有没有访问临界资源,如有则必须仔细分析其互斥的处理过程;
ii. 不一样的可重入函数有没有可能同时进入临界区:读写互斥应该如何去考虑;
下面,一样地,经过孟宁老师所给出的代码,咱们选择一段代码来加以解释:
在须要进入临界区时,咱们对代码进行了加锁操做以确保其余函数没法使用临界区的资源,当咱们退出临界区后及时解锁供以其余函数访问,最后销毁互斥锁,这就是一个典型的线程安全代码。
孟宁老师于课堂上讲解的各个知识点,使我对软件工程中的开发思想、方法有了更深一步地理解。同时,通过这篇博客的书写,我对这些知识的理解更上一层楼了,更为重要的是,动手能力也有所提升,在此深表感谢。
最后,再次强调,参考资料于此:软件工程——码农的自我修养