目录
一、计算机语言的发展历程
1. 机器语言(Machine Language):机器语言是计算机能够直接理解和执行的二进制代码,它由一系列的0和1组成。在早期计算机时代,程序员需要手动编写机器语言指令来控制计算机的运行。
2. 汇编语言(Assembly Language):汇编语言使用助记符号和地址符号来代替二进制代码,使得程序员能够以更易读的方式编写程序。
3. 高级语言(High-Level Language):高级语言是相对于汇编语言而言的。它是以“人”的思维逻辑来描述电脑运行的语言。它使用更接近自然语言的语法和结构,使得程序编写更加方便和易读。高级语言的代码需要通过编译器或解释器转换为机器语言才能在计算机上运行。Fortran(1957年)和Lisp(1958年)是早期的高级语言之一。
4. 第一代高级语言(1950s - 1960s):在高级语言的发展过程中,出现了一系列的第一代高级语言,如Fortran、Lisp和COBOL。这些语言主要用于科学计算、符号处理和商业应用等领域。
5. 第二代高级语言(1960s - 1970s):在第二代高级语言的阶段,出现了一些具有重要影响力的编程语言,如ALGOL、BASIC和C语言。其中,C语言的出现标志着高级语言的一个重要里程碑,它成为后来很多编程语言的基础,并对计算机操作系统的开发产生了深远影响。
6. 第三代高级语言(1980s - 至今):在第三代高级语言的时期,许多现代编程语言如C++、Java和Python等相继诞生。这些语言更加注重开发效率、可移植性和软件工程的规范化。
二、程序的执行方式
我们使用编程语言是为了写下要计算机做的步骤,让计算机去执行。计算机做的所有事情都叫计算,包括运算、画图等等。我们要让计算机做计算,就需要找出计算的步骤(算法),然后用编程语言写出来。计算机只懂二进制语言,如何让编程语言编程计算机可读懂的语言呢?
程序执行方式 | 原理 | 优势 | 劣势 |
---|---|---|---|
编译 | 把程序翻译成计算机真正能懂的语言——机器语言写的程序(二进制指令),也就是生成一个可执行程序(比如 Windows 下的 .exe 文件),例如C、C++、Go等,它们都属于编译型语言,使用的转换工具称为编译器。 | 速度快、效率高,一次编译,无限次运行;由于要经历完整编译过程,因此在程序有任何语法错误都能在编译期被发现,大大降低程序的运行错误。 | 生成的二进制代码对平台依赖性强,由于不同操作系统对可执行文件的内部结构有着截然不同的要求,所以可执行程序不能跨平台。此外不同平台支持的函数、类型、变量等都可能不同,源代码同样不能跨平台;这类语言编写的程序每次修改都要再次经历一遍完整编译过程后,修改效果才能生效,迭代时间会比解释型语言要长。 |
解释 | 借助一个程序,那个程序能试图理解你的程序,然后按照你的要求执行,无需预先编译,每次执行程序都需要一边转换一边执行,用到哪些源代码就将哪些源代码转换成机器码,用不到的则不进行任何处理,使用的转换工具称为解释器。由解释器逐行对源码进行解释,一边解释一边执行。比如 Python、JavaScript、PHP等,这类编程语言称为解释型语言。 | 可移植性好,一次编写,到处运行。解释型语言之所以能够跨平台,是因为有了解释器这个中间层。在不同的平台下,解释器会将相同的源代码转换成不同的机器码,解释器帮助我们屏蔽了不同平台之间的差异性。 | 由于每次执行程序都需要重新转换源代码,效率较低; |
除编译型和解释型语言外,还有一种半编译半解释型语言,比如 Java和 C#等,这类语言将源代码先转换成一种中间文件(字节码文件),然后再将中间文件拿到虚拟机中执行。解释器或虚拟机是针对特定平台进行开发的,能够在不同的操作系统和硬件上提供一致的运行环境。这些中间代码可以在不同的操作系统和硬件平台上运行,只要有相应的解释器或虚拟机支持即可。
对于计算机编程语言来说,语言本身是没有编程和解释之分的,任何一种语言既可以编译执行也可以解释执行,这只是传统和习惯的问题,我们常说的编译型语言或解释型语言只是某种语言常用的执行方式。过去解释性语言运行较慢,但是由于现在的计算机速度非常快,所以效率已经不是问题。今天来说,这两种方式已经没有太大区别。
静态语言和动态语言
静态语言 |
|
---|---|
动态语言 |
|
三、C语言的历史发展
C语言是从B语言发展而来,B语言是从BCPL发展而来的,向前追溯C语言最早的原型是ALGOL 60。BCPL和B都支持指针,所以C也支持了并进行了更好的发展,指针是C语言的灵魂,一定要重点学习。关于C语言的历史大家可以查看C语言百度百科进行了解。
BCPL,1967年由剑桥大学的Matin Richards在同样由剑桥大学开发的CPL语言上改进而来。BCPL最早被用做牛津大学的OS6操作系统上面的开发工具。后来通过美国贝尔实验室的改进和推广成为了UNIX上的常用开发语言。
20世纪60年代,美国AT&T公司贝尔实验室的研究员肯尼斯·蓝·汤普森(Kenneth Lane Thompson)闲来无事,手痒难耐,想玩一个他自己编的,模拟在太阳系航行的电子游戏——Space Travel。他背着老板,找到了台空闲的小型计算机——PDP-7。但这台电脑没有操作系统,而游戏必须使用操作系统的一些功能,于是他着手为PDP-7开发操作系统。后来,这个操作系统被命名为——UNICS(Uniplexed Information and Computing Service)。
1969年美国贝尔实验室的Ken Thompson,以BCPL语言为基础,设计出很简单且很接近硬件的B语言(取BCPL的首字母),并且用B语言写了初版UNIX操作系统(叫UNICS)。
1971年,同样酷爱Space Travel的丹尼斯·里奇为了能早点儿玩上游戏,加入了汤普森的开发项目,合作开发UNIX。他的主要工作是改造B语言,使其更成熟。
1972年,美国贝尔实验室的丹尼斯·里奇在B语言的基础上最终设计出了一种新的语言,他取了BCPL的第二个字母作为这种语言的名字,这就是C语言。
1973年初,C语言的主体完成。汤普森和里奇迫不及待地开始用它完全重写了UNIX。此时,编程的乐趣使他们已经完全忘记了那个“Space Travel”,一门心思地投入到了UNIX和C语言的开发中。随着UNIX的发展,C语言自身也在不断地完善。在开发中,他们还考虑把UNIX移植到其他类型的计算机上使用。机器语言和汇编语言都不具有移植性,为x86开发的程序,不可能在Alpha、SPARC和ARM等机器上运行。而C语言程序则可以使用在任意架构的处理器上,只要那种架构的处理器具有对应的C语言编译器和库,然后将C源代码编译、连接成目标二进制文件之后即可在那种架构的处理器运行。因此,Unix和C语言可以说是相辅相成的,它们的密切关系对于现代计算机科学的发展产生了深远的影响。
关于C语言的标准,最早来自于Brian Kernighan和Dennis Ritchie出版的《The C Programming Language》一书,通常简称为K&R C,这是世界上第一本介绍C语言的书,而K&R风格即指他们在该书中书写代码所使用的风格。K&R C语言指的是这本书中所描述的C语言的子集,这个子集在C语言标准制定之前非常流行,也被广泛使用。但是,在K&R C中并没有定义一个完整的标准C语言。我们也把K&R C之后的C语言实现和编码风格以及ANSI C标准化之前的C语言版本称为经典C。
在1982年,很多有识之士和美国国家标准协会(ANSI)为了使C语言健康地发展下去,决定成立C标准委员会,建立C语言的标准。 1989年,ANSI发布了第一个完整的C语言标准——ANSI X3.159-1989,简称“C89”,不过人们也习惯称其为“ANSI C”。C89在1990年被国际标准化组织(International Standard Organization,ISO)一字不改地采纳,ISO官方给予的名称为:ISO/IEC 9899,所以ISO/IEC9899:1990也通常被简称为“C90”。1999年,在做了一些必要的修正和完善后,ISO发布了新的C语言标准,命名为ISO/IEC 9899:1999,简称“C99”。在2011年12月8日,ISO又正式发布了新的标准,称为ISO/IEC9899:2011,简称为“C11”。
如今,C语言的应用已经非常广泛,尽管新的语言层出不穷,但C语言仍是最为基础且非常重要的编程语言。C语言在工业界有重要地位,在很多领域都无可替代,如做操作系统、嵌入式系统都需要C语言。
四、C语言的特点
1. 语言简洁,且表达能力强,使用灵活,易于学习和应用。
2. 强大的指针支持,C语言提供了指针的概念,允许程序员直接操作内存地址。指针可以用于动态分配内存、数组操作、函数传递等,提供了更高级别的灵活性和控制能力。
3. C语言可以直接操作内存,对计算机硬件资源的利用非常高效。C语言的编译器可以将源代码直接编译成机器语言,使得程序的执行速度快。
4. 可移植性好,可以在不同的平台上编写和运行。C语言的标准库提供了丰富的函数和工具,使程序能够在不同的操作系统和硬件平台上进行编译和执行。
5. C语言具有丰富的标准库和第三方库支持,这些库提供了各种功能和算法的实现,使程序员能够更快速地开发复杂的应用程序。
6. C语言支持函数封装和模块化编程,使程序可以以模块的形式组织和扩展。这种可扩展性使得大型项目的开发更加便捷,并促进了代码重用和维护的效率。
五、C语言编译器
在C语言被用作系统编程语言之前,Tompson也用过B语言编写操作系统。因此第一个C语言编译器的原型完全可能是用B语言或者混合B语言与PDP汇编语言编写的。B语言的效率比较低,但是如果全部用汇编语言来编写,不仅开发周期长、维护难度大,更可怕的是失去了高级程序设计语言必需的移植性。所以早期的C语言编译器就采取了一个取巧的办法:先用汇编语言编写一个C语言的一个子集的编译器,再通过这个子集去递推完成完整的C语言编译器。详细过程如下:
先开发一个简单的C语言子集,即C0语言,并使用汇编语言编写了C0的编译器。然后,他们以C0为基础,设计了更复杂但仍不完整的C语言子集,称为C1语言,并开发了C1语言的编译器。随后,他们继续以C1为基础,设计了更复杂的C2语言,以此类推直到CN语言。每个子集都比前一个子集复杂一些,但仍然不是完整的C语言。这样的渐进式开发使得在每个阶段都可以利用已有的功能来实现更高级的语言特性,直到达到完整的C语言的实现。确定N的大小取决于目标语言(即C语言)的复杂程度和程序员的编程能力。当达到某个阶段时,就可以方便地利用现有功能来实现完整的C语言。
随着C语言的出现和发展,Ken Thompson和Dennis Ritchie等人决定使用C语言重新实现Unix系统。因此,最初使用UNIX都会自带一个C语言编译器cc,"cc"是"Unix C Compiler"的简称,也可以指代其他C语言编译器,具体取决于系统和环境。
后来GNU做了一个编译器GCC,经过不断发展被广泛使用。GNU的全称是“GNU's Not Unix”,这个名称反映了GNU项目的目标:构建一个类Unix操作系统,它是完全自由和开源的,没有任何专有技术或代码。GNU是一个自由软件运动的项目,由理查德·斯托曼(Richard Stallman)在1983年发起,并由自由软件基金会(FSF)支持。GNU项目的目标是创建一个由完全自由软件组成的操作系统,以便用户可以自由地使用、复制、修改和分发软件。为此,GNU项目创建了一系列自由软件工具和组件,如GNU编译器套件(GCC)、GNU调试器(GDB)等。第一个版本的GCC由理查德·斯托曼开始开发,并于1987年发布。GCC的初衷是为GNU操作系统专门编写的一款编译器,现已被大多数类Unix操作系统(如Linux、BSD、MacOS X等)采纳为标准的编译器,甚至在微软的Windows上也可以使用GCC。GCC支持多种计算机体系结构芯片,如x86、ARM、MIPS等,并已被移植到其他多种硬件平台。GCC原名为GNU C语言编译器(GNU C Compiler),只能处理C语言。但其很快扩展,变得可处理C++,后来又扩展为能够支持更多编程语言,如Fortran、Pascal、Objective -C、Java、Ada、Go以及各类处理器架构上的汇编语言等,所以改名GNU编译器套件(GNU Compiler Collection)。
编译器套件是指由多个编译器和相关工具组成的软件包。它们被设计用于将源代码转换为可执行代码或其他目标代码,并提供了一系列的工具来支持编译、链接和调试等任务。一个完整的编译器套件通常包括以下组件:
1. 编译器:编译器是编译器套件中最重要的组件之一。它负责将源代码转换为目标代码,即将高级语言编写的程序翻译成机器能够理解和执行的指令集。
2. 预处理器:预处理器是编译器套件中的一部分,用于对源代码进行预处理。它会执行一系列的文本替换、宏展开和条件编译等操作,以生成经过处理的源代码。
3. 汇编器:汇编器将汇编语言代码转换为机器码指令,它将汇编语言表示的程序翻译成二进制形式的指令序列。
4. 链接器:链接器将编译后的目标文件以及相关的库文件链接在一起,生成可执行文件或者动态链接库。链接器还负责解决符号引用和地址重定位等任务。
5. 调试器:调试器是一个用于调试程序的工具,它允许开发人员逐行执行程序、查看变量的值、设置断点等,以便追踪和修复程序中的错误。
GCC执行过程示例
示例代码
#include<stdio.h>
int main(void)
{
printf("Hello,World\n");
return 0;
}
预编译过程
预编译是做些代码文本的替换工作。处理以# 开头的指令 , 比如拷贝 #include 包含的文件代码、#define 宏定义的替换 、条件编译、去除注释等,不会对语法进行检查,就是为编译做的预备工作的阶段。可以看到预编译后,代码从6行扩展到了910行。这个结果意味着预处理之后的 a.i 文件比源代码文件 a.c 要长得多。这是因为预处理器会将头文件(如 stdio.h)中的内容包含到源代码文件中,从而生成了一个更加详细和复杂的文件。
gcc -E a.c -o a.i //对a.c文件进行预处理操作
cat a.c|wc -l //输出文件a.c中的行数
5
cat a.i|wc -l //输出文件a.i中的行数
910
编译过程
这个阶段,检查语法,生成汇编代码。
gcc -S a.i -o a.s
cat a.s|wc-l
59
汇编过程
gcc -c a.s -o a.o //对文件"a.s"进行汇编,生成目标文件"a.o"
file a.o //查询文件"a.o"的类型
a.o:ELF64-bitLSBrelocatable,AMDx86-64,version1(SYSV),notstripped //显示文件类型
/*
这个信息可以分解为以下几个部分
"ELF":表示该文件是一种可执行和链接格式(Executable and Linkable Format)文件,常见于Linux系统。
"64-bit":表示该文件是一个64位的二进制文件。
"LSB":表示该文件遵循小端序(Little Endian)排列方式。
"relocatable":表示该文件是一个可重定位文件(Relocatable file),还没有进行最终的链接。
"AMD x86-64":表示该文件是针对AMD x86-64架构的目标文件。
"version 1 (SYSV)":表示该文件遵循System V ABI规范的第一版。
"not stripped":表示该文件未被去除符号表等调试信息。
*/
链接过程
生成可执行代码。链接分为两种,一种是静态链接,另外一种是动态链接。使用静态链接的好处是,依赖的动态链接库较少,对动态链接库的版本不会很敏感,具有较好的兼容性;缺点是生成的程序比较大。使用动态链接的好处是,生成的程序比较小,占用较少的内存。
gcc a.o -o a //将目标文件a.o链接成可执行文件a
程序运行
./a //运行当前目录下名为a的可执行文件
Hello,World
当我们输入"./文件名"来运行程序时,操作系统会加载这个可执行文件,分配内存空间,并开始执行程序。这个过程不需要GCC的参与,因为GCC的工作已经完成,它只是生成了一个可执行文件,并将程序的运行时需要的库和函数链接到了一起。可执行文件中已经包含了程序的全部信息,包括代码、数据、符号表等,可以直接被操作系统执行。需要注意的是,虽然可执行文件已经包含了程序的全部信息,但仍然可能会出现各种错误和异常,如内存泄漏、段错误等。如果需要定位这些问题,还需要使用调试器进行调试,如GDB。GDB是GNU调试器的缩写,是一个强大的命令行调试工具,支持多种编程语言和多种平台。开发人员可以使用GDB来调试程序,以便查找和修复错误。GDB提供了一系列的功能,如设置断点、单步执行、查看变量和寄存器等,可以帮助开发人员定位程序中的问题。
JDK是Java开发工具包(Java Development Kit)的缩写,它是用于开发Java应用程序和Applet程序的软件开发工具包。JDK包括了Java运行时环境(JRE)、Java编译器(javac)、Java调试器(jdb)以及其他用于开发、调试和运行Java程序所需的工具和库。通过JDK,开发人员可以编写、编译和调试Java程序,并将其部署到各种平台上运行。要运行Java文件,需要先使用javac命令编译Java源程序,例如:
javac hello.java
,如果编译通过,会在当前目录下生成一个名为hello.class的字节码文件。然后使用java命令运行字节码文件,此处使用了虚拟机(JVM)运行字节码文件,JVM可以解释和执行Java字节码文件,将其转换为具体的机器指令,使得Java程序可以在不同的操作系统和硬件平台上运行。
GCC在Windows上的运行
若要在Windows上使用GCC,需要安装一个可以在Windows上运行的GCC版本。通常情况下,我们可以从MinGW项目或者Cygwin项目中下载和安装GCC。MinGW(Minimalist GNU for Windows)是一个开源项目,旨在为Windows提供一个轻量级的GNU开发环境。它包括了编译器、调试器以及其他一些必要的工具和库文件,可以用来编译和运行大部分的GNU软件,也可以用于开发Windows本地应用程序。Cygwin是另一个开源项目,它提供了一个完整的POSIX(可移植操作系统接口,使得软件能够在不同的操作系统上编写和运行)环境,包括了编译器、调试器以及其他一些必要的工具和库文件,可以用来开发和运行Unix/Linux程序,同时也可以编译和运行Windows本地应用程序。
MinGW和Cygwin的区别
操作系统会为应用程序提供接口,因此可以在Windows系统中使用GCC进行开发。除了GCC之外,对于将C源代码编译为可执行程序.exe,如使用printf,则需要使用合适的库和工具。在Windows上,可以使用MinGW和Cygwin两种方式。
Cygwin提供的库是用于在Windows上模拟Unix-like环境,通过对POSIX系统调用的模拟来实现与Unix兼容的环境。因此,在Cygwin环境中可以运行许多基于Unix的软件,包括bash shell、GNU编译器套件(GCC)、Emacs等。使用Cygwin编译出的程序虽然会在Windows上执行,但它们是通过模拟Unix-like环境来实现的,并非在原生的Windows环境中执行。因此,虽然在Windows上运行,但其运行时环境类似于Unix系统,因此可视为在Windows上运行的Unix程序。这也意味着如果使用Cygwin编译出的程序在没有安装Cygwin环境的系统上运行,可能会遇到兼容性问题。
MinGW是一个用于在Windows上构建本地Windows应用程序的工具集。它提供了一组GNU工具,包括GCC、GNU binutils等,同时还提供了一些Windows API的头文件和库。MinGW的目标是通过使用本地Windows API来构建Windows应用程序,而不是模拟Unix环境。使用MinGW,我们可以使用GCC来编译C代码,然后链接到Windows API的库(称为winlib),生成可在Windows上运行的可执行文件(.exe)。因此,MinGW提供了更原生的Windows开发体验,可以方便地构建和运行Windows应用程序,并且通常性能较高。
随着C语言标准的不断迭代,GCC支持包括C89/C90、C99、C11在内的C语言标准。需要注意的是,不同版本的GCC可能对C语言标准的支持程度有所差异。因此,在使用GCC进行C语言编译时,建议查阅相关版本的GCC文档以确认所支持的C语言标准及其特性。此外,GCC还提供了一些扩展功能,可以使用特定的命令行选项来启用这些扩展功能,但这些扩展是非标准的,可能导致代码在其他编译器上不可移植。
后来windows变成主流,出现了面向Windows平台开发的VC编译器(Visual C++)。此外,还有由苹果公司发起,旨在创建一个更快、更现代化的C/C++/Objective-C编译器Clang。该项目以LLVM(Low Level Virtual Machine,底层虚拟机,提供了与编译器相关的支持,能够进行程序语言的编译期优化、链接优化、在线编译优化、代码生成。简而言之,可以作为多种编译器的后台来使用)作为后端,并且专注于提供更好的错误信息、更快的编译速度和更好的代码质量。随着时间的推移,Clang逐渐成为开源社区中备受关注的项目,并在多个平台上得到了广泛的应用。
六、C语言集成开发环境(IDE)
常用的C语言IDE包括Dev-C++、Code::Blocks、Visual Studio、VS Code等。
Dev-C++是一个轻量级的C/C++ IDE,特别适合Windows平台。它提供了简单易用的界面、快速编译和调试功能,安装过程比较简单,只需按照步骤进行即可。Dev-C++默认使用的调试工具是GDB,在Dev-C++中,可以通过菜单栏的“Debug”选项来启动和使用GDB调试器。在调试过程中,可以设置断点、查看程序的状态、执行程序的不同代码路径等。同时,Dev-C++还提供了一些调试工具,如内存泄漏检测器、性能分析器等,可以帮助开发人员进一步优化程序的质量和性能。
Code::Blocks则是一个开源的、跨平台的C/C++ IDE,适合初学者。它提供了简洁的界面、强大的编辑器和调试器,可以在Windows、Linux和macOS上运行。关于Code::Blocks的安装也比较简单,如果安装路径更换的话可能存在一些问题,具体可查看CodeBlocks下载与安装教程https://blog.csdn.net/ysz171360154/article/details/84572114
两者区别
Dev-C++ 默认集成了 MinGW 编译器套件,而 Code::Blocks 不附带特定的编译器,可以根据需要选择和配置不同的编译器。在 Windows 平台上,Code::Blocks 可以与 MinGW 编译器套件一起使用。除了 MinGW,Code::Blocks 还支持其他编译器,例如 Clang 和 Microsoft Visual C++ 等。用户可以根据自己的需要选择适合的编译器,并在 Code::Blocks 中进行配置。Code::Blocks 提供了插件系统,允许用户根据需要扩展和定制 IDE 的功能。Dev-C++ 没有类似的插件支持。Code::Blocks 可以在多个平台上运行,Dev-C++ 仅适用于 Windows 平台。
Visual Studio是由微软开发的全功能IDE,它提供了丰富的功能和工具,包括代码编辑、调试、性能分析、图形界面设计等,适用于Windows平台。它支持多种编程语言,包括C语言,并且有一个庞大的扩展生态系统,可以安装各种插件来扩展功能。Visual Studio 适用于各种规模的项目,包括桌面应用、Web 应用、移动应用等。Visual Studio 在功能和扩展性方面更加强大,适用于中大型的、多人合作的项目开发。如果你需要处理较大规模的项目或者需要使用更高级的功能和工具,建议选择 Visual Studio。
除了上述IDE之外,还有其他一些可以用于C语言开发的工具,例如GCC、LLVM/Clang等编译器配合文本编辑器(如Vim、Emacs、Sublime Text)也可以进行C语言开发。
VS Code是一个非常好用的轻量级的代码编辑器,是一款由微软开发的免费、开源的跨平台文本编辑器,它具有许多IDE的功能,并且支持大量的编程语言。虽然 VS Code 可以用于编写和调试代码,但它更注重于提供优秀的代码编辑体验。VS Code 提供了丰富的编辑功能,如智能代码补全、语法高亮、代码片段等。它还支持版本控制、调试工具、终端集成等功能,使开发者能够更高效地进行开发工作。尽管 VS Code 不像传统的 IDE 那样提供完整的项目管理和构建功能,但通过安装适当的插件和扩展,可以将其功能扩展到更接近 IDE 的水平。这使得 VS Code 成为许多开发者喜爱的选择,尤其是对于小型项目、脚本编写和前端开发等场景。但是使用VS Code运行C语言程序较为麻烦,需要进行一些配置。