1.1 程序及程序设计语言
程序可看作为解决某种信息处理任务而预先编制的工作执行方案。每个程序都是使用某种程序设计语言编写出来的。程序设计语言种类繁多,其形式、应用范围、对计算机硬件和软件环境的适应性等各个方面都各有侧重,但大体上可归结为3种:机器语言、汇编语言和高级语言。其中高级语言中描述数据和操作步骤的方式接近于人们日常所用的数学表达式或者自然语言,具有使用方便、通用性强等多种优点。C#就是一种高级语言。
1.1.1 程序的一般结构
早期计算机中的程序是采用“机器语言”[1]编写的,一个程序中包含若干条计算机能够直接执行的机器指令,每条指令都规定了计算机应该执行的操作(加法、减法、数据传送、转移、停机等)以及执行时所需要的数据。例如,从存储器读一个数送到运算器就是一条指令,从存储器读出一个数并和运算器中原有的数相加也是一条指令。
在使用计算机求解实际问题时,设法将求解过程分解为一个个便于计算机执行的操作步骤,并将每个步骤都用一条或多条指令编写出来,构成解决指定问题的程序。再将已编好的程序送入计算机,以二进制代码形式存放在存储器中。一旦程序被“启动”,计算机便会按照程序中指定的逻辑顺序一条条地分析执行所有指令,从而一步步地完成给定的任务。
存储程序功能使得计算机变成一种自动运行的机器,将程序存入计算机并启动它,计算机就可以独立地工作,以电子速度一条条地执行指令。虽然每条指令所做的工作都很简单,但通过程序中一系列指令的连续执行甚至程序与程序之间的协同工作,计算机就能够完成极其繁重的任务。
电子计算机是人类设计制造的增强人类信息处理能力的工具,可看作人类头脑功能的延伸,自然具备人类处理问题的特点。在日常的生产和生活中,人类需要面对各种各样的问题,尽管问题的内容和形式多种多样,解决的方法也千差万别,但一般来说,其基本过程可大致归结为3步。
第1步,接受原始信息,通过眼耳等感知相关的原始信息,将其记忆在大脑的相应功能区,或者通过手口等记录在纸或录音、录像设备上。
第2步,分析处理信息,通过大脑并借助其他工具和手段对已获取的信息进行综合分析处理,主要包括以下几个方面。
• 综合分析相关信息,建立信息之间的总体联系,如数量关系、逻辑关系等,并将其记忆在大脑、纸或录音、录像设备上。
• 运用某些基本信息,主要是在解决问题之前已记忆在大脑中的经验、方法、技巧、知识等,对信息之间的总体联系进行数学推演或逻辑推理,得出中间结果和最终结果,并将其记忆在大脑、纸或录音、录像设备上。
• 根据原始信息、相关信息和基本信息,核验所得结果信息,特别是最终结果的可靠性、合理性和正确性,必要时,还可借助各种设备来进行。
第3步,表达出最终答案,经过核验确认是正确的最终结果将通过感官输出。例如,通过报表的形式向有关部门汇报,通过讲演的形式进行宣传,或通过书籍、电子文档等形式提供给公众。
上述人处理问题的基本方式可形象地表现出来,如图1-1所示。
图1-1 人解题的基本方式
程序的基本工作方式与人处理问题的方式十分相似。可将程序看作一个函数F(),它接收原始数据集合X,经过运算处理,产生结果数据集合Y,即
Y=F(X)
例1-1 根据下面的函数,由已知的x值计算y值。
程序要完成的任务如下。
• 接受用户输入(使用键盘或其他设备)的x值。
• 根据该值所属范围,调用相应的数学式计算y值。
• 输出y值。
这个程序既可以用机器能够直接执行的“机器语言”来编写,也可以用BASIC、C或者C#等各种高级语言来编写。这里给出用C#语言编写的程序的主要内容。
class Program { static void Main(string[] args) { int x, y; x=Convert.ToInt16(Console.ReadLine()); if (x >= 0) y = 2 * x + 1; else y = -x; Console.WriteLine("y={0}", y); } }
注意
C#编译器区分字母的大小写,即将大写字母和相应的小写字母当作不同的字符。
这一段代码是名为Program的“类”的定义,由关键字“class”标识,其内容位于一对花括号“{”和“}”之间。其中包含一个名为“Main”,由一对花括号“{”和“}”定界的“方法”,方法中包含一些C#语言的“语句”,可将这些语句划分为3部分:数据的输入部分、运算部分和运算结果的输出部分。
(1)数据的输入及其定义部分。
赋值语句
x=Convert.ToInt16(Console.ReadLine());
负责输入程序中要用到的原始数据。该语句的功能是:等待用户从标准输入设备(键盘)上输入一个数据,将其转换为整型数并赋值给变量x。
C#语言规定:程序中要用到的所有变量都必须先定义,然后才能使用。故在这个赋值语句之前,先要用类型定义语句
int x, y;
定义变量x以及后面要用到的变量y。
(2)运算部分。
以“if”开头的条件语句
if (x>=0) y=2*x+1; else y=-x;
完成程序中的运算任务。该语句的功能是:判断x值的范围,如果x≥0,则按y=2x+1计算y值;如果x<0,则按y=-x计算y值。
在这个语句中,嵌入了两个赋值语句
y=2*x+1; y=-x;
其功能都是:计算等号右边表达式的值,并将计算的结果赋予等号左边的变量。
(3)运算结果输出部分。
输出语句
Console.WriteLine("y={0}", y);
负责输出运算结果,即输出按照给定的分段函数和已知的x值计算得到的y值。语句的功能是:将y值按默认的格式输出到标准输出设备(显示器)上。
该程序在执行后,屏幕显示
自变量x=?
以及输入提示符(一个闪烁的短画),等待用户输入。当用户输入一个数字(如9)并按回车键后,屏幕显示运算结果,如:
19
程序再次运行后,在输入提示符后再输入另外一个数字并按回车键,屏幕还会显示相应的运算结果。
1.1.2 程序设计语言
程序描述了计算机处理数据、解决问题的过程,这是程序的本质。但程序对数据和问题的描述方式却是多种多样的。随着计算机技术的不断进步,程序设计语言的形式和种类也在不断地发展变化。按照程序设计语言发展的先后,大体上可将其分为3种:机器语言、汇编语言和高级语言。
1. 机器语言
能被计算机直接理解和执行的指令称为机器指令,它在形式上是由“0”和“1”构成的一串二进制代码,每种计算机都有自己的一套机器指令。机器指令的集合就是机器语言。
机器语言是计算机诞生和发展初期使用的语言,它和人们习惯使用的语言,如自然语言、数学语言等差别很大,直接使用机器语言来编写程序是一种十分复杂的手工劳动。例如,下面给出的一条机器指令的功能是:从指定的内存单元取出数据,装入指定的寄存器。
10001011 00000101 00000000 01111001 10001111 10101101
可以看出,这种机器指令难以理解,编写出来的程序不易修改,也无法从一种计算机环境移植到另一种环境中去,因此很难用来开发实用的程序。
2. 汇编语言
为了克服机器语言的缺点,人们采用了一些特定符号(称为助记符)来取代原机器指令中的二进制指令代码,如用ADD表示加法,用SUB表示减法等。同时又用变量取代各类地址,如用A取代地址码等。这样构成的计算机符号语言,称之为汇编语言。用汇编语言编写的程序称为汇编语言源程序。例如,汇编语言语句
MOV AX, DATA1
的功能与前面的机器指令相当,用于从DATA1变量所占用的内存单元中取出数据(称为DATA1变量的值),装入AX寄存器(CPU或者运算器中暂存少量数据的器件)。
汇编语言程序必须经过翻译(称为汇编)变为机器语言程序,才能被计算机识别和执行。
汇编语言在一定程度上克服了机器语言难于辨认和记忆的缺点,但汇编语言程序的大部分语句还是和机器指令一一对应的,更接近于机器语言而不是人使用的自然语言,而且汇编语言都是针对特定的计算机而设计的,对机器的依赖性仍然很强。因而,对大多数用户来说,汇编语言仍然是不便理解和使用的。
只适用于某种特定类型的计算机的程序设计语言称为面向机器的语言,机器语言和汇编语言都是这种语言,这两类语言也称为“低级”语言。
3. 高级语言
为了克服低级语言的缺点,出现了“高级程序设计语言”,这是一种类似于“数学表达式”,接近自然语言(如英文),又能为机器所接受的程序设计语言。高级语言具有学习容易、使用方便、通用性强、移植性好的特点,便于各类人员学习、掌握和应用。例如,使用C#语言,按照给定的数学式编写的依据x值计算y值的语句为
y = 5 * Math.Sqrt(x + 1);
用高级语言编写的程序(称为源程序)不能直接在计算机上执行,必须经过相应的翻译程序翻译成机器指令表示的目标代码,然后才能在计算机中执行。
使用高级语言编写程序时,用户不必记忆计算机指令繁杂的格式和写法,不必考虑数据在存储器中的具体存放位置和顺序,可以在更高的层次上考虑解决问题的算法。因而,目前绝大部分程序设计任务都是通过高级语言来完成的。但机器语言和汇编语言并未因此而销声匿迹。在某些程序的关键部分,如操作系统的内核等,仍需要用汇编语言甚至机器指令来编写。而且,由汇编语言编写的程序的代码质量较高,这一点是高级语言程序无法比拟的。
4. 高级语言的种类
从20世纪50年代出现第一种高级语言FORTRAN起,多种多样的高级语言层出不穷。以下是几种出现较早或者影响较大的高级语言。
(1)FORTRAN语言:是最早产生的高级语言,适合于处理公式和进行数值计算。它的产生和发展曾经极大地推动了计算机的普及和应用。
(2)ALGOL语言:是紧随FORTRAN语言之后产生的高级语言,也是第一个清晰定义的语言,其语法是用严格公式化的方法说明的。ALGOL语言并未被广泛地使用,但它是许多现代程序设计语言的概念基础。
(3)BASIC语言:曾经被看作为易于学习和使用的语言,并用于一般的科技计算以及小型数据处理等许多方面。目前流行的Visual Basic就是由BASIC语言发展而来的。
(4)Pascal语言:是系统地体现结构化程序设计[2]思想的高级语言。它在支持结构化程序设计和表达各种算法,尤其是非数值型算法上比其他语言都要规整和方便,曾经是书写算法、计算机软件教材、进行计算机教学的首选语言。Delphi(Object Pascal)语言就是由Pascal语言发展而来的。
(5)C语言:是一种功能强、使用灵活的语言。C语言编写的程序简洁、易修改而且运行效率高。C语言既有高级语言的优点,又有汇编语言的某些特点,很适合于开发系统软件或者应用软件。很多著名的软件(如UNIX)都是C语言编写的。C语言本身也在不断改进,C++、Java和C#语言都可以在某种程度上看作为C语言的提高版。
5. 高级语言的执行方式
在计算机上执行高级语言编写的程序有两种基本方式:编译方式和解释方式。
编译方式是将高级语言源程序送入计算机后,调用编译程序(事先设计的专用于翻译的程序)将其整个地翻译成机器指令表示的目标程序,然后执行目标程序,得到计算结果,如图1-2所示。
在编译过程中,编译器首先检查源程序是否符合语言的形式规定,称为“语法检查”,只有语法正确的程序才能进行后续的加工变换,并生成对应的目标代码。Pascal语言、C语言都是编译型的语言。
解释方式是在高级语言源程序输入计算机后,启动解释程序,翻译一句执行一句,直到程序执行完为止,如图1-3所示。BASIC语言是解释型的语言。
图1-2 高级语言的编译方式
图1-3 高级语言的编译方式
6. 程序设计语言现状
随着计算机应用的日益普及,程序设计(软件开发)技术也不断进步,各种程序设计语言(软件开发工具)层出不穷。今天,许多程序设计语言已经和传统意义上的语言有很大的不同了。它们不但功能强大,而且程序或者软件的形式以及程序设计或者软件开发的方式等都有极大的改进。例如,目前流行的RAD(Rapid Application Development,快速应用开发工具)、如VB(Visual Basic)、Power Builder、Delphi、Visual C#等,普遍采用可视化编程技术,用户只需依据屏幕的提示回答一连串问题,或在屏幕上执行一连串选择操作之后,编写少量代码甚至不必编写代码就可以自动形成程序。
注意
软件是程序以及相关文档(使用、维护等文字材料)的统称。软件开发是一个从软件需求分析到软件设计再到程序设计、测试,最终实现实际需求的完整过程。也就是说,程序设计是软件开发中的一环,而且往往是最重要的一环。
1.1.3 C#语言与.NET框架
C#是微软公司发布的一种面向对象的、运行于.NET框架之上的高级程序设计语言。而Microsoft Visual Studio是微软推出的集成开发环境,可用于创建在.NET框架上运行的基于包括C#在内的多种语言(C++、Visual Basic等)的应用程序。
1. C#语言的起源
今天,计算机技术已在很大程度上融入了无所不在的信息网络、千变万化的应用环境乃至普罗大众的日常生活之中。各种生产设备(如数控机床)、仪器仪表以及消费类电子(如移动电话)等都需要相应的程序(软件)来运转。千变万化的应用环境催生出了五花八门的程序设计工具,也产生了多种多样新的问题和新的需求。例如,如何将基于不同的程序设计语言的软件组件集成在一起?如何在特定的系统或者环境中安装软件?如何解决新软件与旧软件或者软件的新版本与旧版本的共享组件的兼容性问题?如何开发出使用各种不同设备(桌面计算机、移动数字设备等)的用户都能够访问的软件系统?如何开发出基于Web的软件,以便用户通过Internet访问和使用?
为了满足这些需求,微软公司在2000年之际推出了基于.NET平台的C#程序设计语言,C#语言是在C++语言和Java语言的基础上形成的,采后二者之所长并增加了自己新的特性。它简化了C++语言在类、命名空间、方法重载和异常处理等方面的操作,像VB一样使用组件编程,因而容易使用且较少出错。
2. .NET框架及C#语言的运行
微软常被看作为一个平台厂商。也就是说,由微软搭建技术平台,再由技术人员在此平台上创建应用系统。实际上,.NET就是微软搭建的技术平台。一个.NET应用就是一个运行于.NET框架之上的应用程序。
.NET框架是微软公司开发的一个多语言组件开发和执行的统一环境。构建.NET框架的目的是便于开发人员更方便地建立Web应用和Web服务,使得Internet上的各种应用程序之间可以通过Web服务进行沟通。从层次结构上看,.NET框架主要包括3个组成部分。
• CLR(Common Language Runtime,公共语言运行时):提供一个运行时环境,其功能通过编译器与另一些工具共同实现,用于管理代码的执行并简化开发过程。
• 一套功能完善的基础类库:包括集合、输入/输出、字符串和数据类等。
• 集成了多种程序设计语言(C#、VB.Net、C++.Net、J#)以及ASP.NET(创建动态Web页工具)、ADO.NET(数据访问接口)的一系列便于使用的可视化组件。
.NET框架中运行的C#源程序先要由C#编译器处理成中间代码MSIL(Microsoft Intermediate Language,微软中间语言)。这种中间语言代码并非CPU可执行的机器码,需要在CLR提供的运行时环境中运行。CLR中的JIT(Just In Time,即时编译器)将MSIL翻译成可执行的机器代码,交由CPU执行,如图1-4所示。
图1-4 C#程序的编译方式
可以看出,.NET应用实际上是使用.NET框架中的类库来编写并运行于CLR之上的应用程序。
注意
如果一个应用程序跟.NET框架无关,它就不能叫作.NET程序。例如,仅仅使用了XML并不就是.NET应用,仅仅使用SOAP SDK调用一个Web Service也不是.NET应用。
3. C#语言的特点
C#语言的CLR与JAVA语言的虚拟机类似。这种执行方法使得程序的运行速度变慢,但却带来了一些好处,主要有以下几点。
(1)满足CLS(Common Language Specification,通用语言规范):.NET系统支持多种语言:C#、C++、VB和J#,这些语言都遵守通用语言规范,其源程序都可以编译成同一种中间语言MSIL代码并由CLR负责执行。这种处理方式称为“托管方式”,这样的代码称为“托管代码”。
注意
只要其他操作系统上配制了相应的CLR,同样可以运行MSIL代码。
(2)自动内存管理:CLR内建了垃圾收集器,当变量实例的生命周期结束时,它负责收回不再使用的实例所占用的内存空间。不必像C和C++语言那样,用语句建立的实例所占用的内存空间就必须用语句来释放。
(3)交叉语言处理:既然任何一种遵守通用语言规范的语言所编写的源程序都可以编译成相同的中间语言代码MSIL,那么,不同语言设计的组件就可以互相通用,例如,可以从VB定义的类派生出C#语言中的新类。由于MSIL代码由CLR负责执行,因此异常处理方法是一致的,这在调试一种语言调用另一种语言的子程序时,显得特别方便。
(4)安全性增强:C#语言不支持指针,一切对内存的访问都必须通过对象的引用变量来实现,只允许访问内存中允许访问的部分,可以防止病毒程序使用非法指针访问私有成员。也避免指针误操作产生的错误。CLR执行MSIL代码前,要对其安全性、完整性进行验证,防止病毒对这种中间语言代码的修改。
(5)版本控制:一个系统中的组件或动态链接库往往需要升级,但可能会因需要在注册表中注册而出现问题。例如,在安装新程序时,新组件替换了旧组件,某些必须使用旧组件的程序就不能运行了。而在.NET中,类似的组件或动态链接库不必在注册表中注册,每个程序都可以使用自带的组件或动态链接库,只要把它们放在运行程序所在文件夹的子文件夹bin中,运行程序就可以自动使用了。由于不必在注册表中注册,软件的安装也变得容易了,一般地,将运行程序及库文件拷贝到指定文件夹中就可以了。
(6)完全面向对象:C#语言是完全面向对象的,不像C++语言那样,既支持面向过程程序设计,又支持面向对象程序设计。C#中不再需要全局函数和全局变量,所有的函数、变量和常量都必须定义在类中,避免了命名冲突。