目录
前言
本文初步介绍C语言的基本特点,万丈高楼平地起,我们从最基础的讲起。
一、C语言的历史和特点
1.C语言历史
C语言是由美国计算机科学家Dennis Ritchie于1972年为了开发UNIX操作系统而创建的一种高级编程语言。C语言最初是作为UNIX操作系统的开发语言而出现的,后来逐渐发展成为一种广泛使用的通用编程语言。
在1983年,美国国家标准化协会(ANSI)确实制定了C语言的标准,这也成为了后来很多C语言版本的基础,包括Turbo C,Microsoft C,Quick C等。这些版本可能在具体的语法、功能和库上有所差异,但都遵循了ANSI C的基本规范。
这些版本的出现,使得C语言在各种不同的系统和平台上得到了广泛的应用和发展。例如,Turbo C是在DOS系统上运行的,Microsoft C则是在Windows系统上开发的,而Quick C则是为图形用户界面(GUI)编程设计的。
此外,在1989年,美国国家标准和技术研究院(NIST)对C语言标准进行了修订,公布了新的标准,通常被称为"C89"或"C90"。这一标准对C语言的语法和语义进行了更严格的定义,进一步提高了C语言的可移植性和一致性。
而在近年来,C语言的最新标准是ISO/IEC 9899,通常被称为"C99"。C99引入了一些新的特性和语法规则,例如支持长长整型(long long)、单精度浮点数(float)、双精度浮点数(double)等数据类型,以及支持可变长度数组(VLA)等。
总的来说,C语言的发展历程充满了标准化和版本化的过程,这些过程使得C语言得以在各种不同的系统和平台上得到广泛的应用和发展。
2.C语言特点
C语言确实具有丰富的数据类型,包括整型、浮点型、字符型、数组类型、指针类型、结构体类型、共用体类型等,这为开发者提供了广泛的选择,可以根据需要选择合适的数据类型来处理不同的数据。
C语言的控制结构语句确实是符合结构化程序设计的要求的,使用函数作为程序模块使得程序结构清晰,易于阅读和调试。这种结构化的编程方式使得代码更易于理解和维护。
C语言的高效率目标代码特性也是其备受喜爱的原因之一。C语言允许直接访问物理地址,直接对硬件进行操作,提供了对字节、位、内存和寄存器的操作功能,甚至可以嵌入汇编语言代码,这些特性使得C语言生成的代码执行效率高,同时也能进行高效的资源利用。
同时,C语言的可移植性非常好,用C语言写的程序基本上可以不加修改地用于各种计算机和操作系统。这使得C语言成为了一种非常通用的编程语言,可以在各种不同的平台上进行开发和运行。
不过C语言也有自己的缺点,作为一种低级语言,因此,编写和调试代码通常需要更长的时间。此外,C语言没有内置的许多现代编程概念,如对象导向编程和高级内存管理,这也会增加实现的复杂性。
C语言的标准并未规定所有可能的实现在所有平台上都是相同的,这使得代码从一个平台移植到另一个平台变得更加困难。不同的编译器和操作系统可能会有不同的行为和特性,这可能会影响代码的行为和效率。
C语言给予程序员很大的自由度,可以在内存管理,指针操作等各个方面进行详细控制。然而,这也意味着程序员需要具备足够的专业知识和经验,才能正确地使用这些特性。如果没有正确的使用,可能会导致各种错误,包括内存泄漏,指针越界等。
C语言标准库相对较小,很多功能需要依赖平台库(如Windows的WinAPI,Linux的glibc等)实现。这增加了代码的复杂性,因为程序员需要熟悉不同平台的库接口和行为。这也降低了可移植性,因为不同的平台可能有不同的库实现。
3.C语言的应用领域
C语言可以写网站后台程序,后台使用C语言作为开发语言。例如,一些高性能的Web服务器和数据库系统使用C语言进行优化。
C语言具有高度的可扩展性和灵活性,可以针对特定的应用领域编写功能强大的程序。例如,针对图像处理、机器学习、数据分析,数据库等领域。
许多大型游戏的引擎都是使用C语言编写的。例如,Valve公司的Source引擎就是使用C语言开发的。
C语言可以发明新的编程语言,有些语言的编译器或解释器是用C语言编写的。
C语言可以写操作系统和驱动程序。在编写操作系统和驱动程序时,需要直接与硬件进行交互,而C语言是一种底层语言,具有这样的能力。
几乎所有的微处理器都支持C语言。事实上,许多嵌入式系统的开发都是使用C语言完成的。
总之,C语言的广泛应用与其高效、灵活、底层等特性密切相关。无论是在底层系统开发、嵌入式系统开发、游戏开发还是其他领域,C语言都发挥着重要的作用。
二、C语言程序的基本结构
1.第一个helloworld程序
程序代码如下(示例):
#include <stdio.h> //编译预处理命令
#include <stdlib.h> //编译预处理命令
int main(void) //程序启动函数
{ //函数开始标志
printf(“Hello world”); //库函数输出字符串helloworld
system(“pause”); // 程序运行至此暂停
return 0; // 函数退出返回值0
} //函数结束标志
C语言程序的基本组成部分:
预处理器指令(以#开头的行):这些指令告诉预处理器在程序执行之前要做的事情,比如包含头文件、定义宏等。
函数:C语言程序由一个主函数(main())和可能的其他函数组成。主函数是程序的入口点。
代码块:由一对大括号{}包围的语句集合。代码块可以嵌套在其他代码块中。
语句:一行代码称为一条语句。每条语句都以分号(;)结尾。
main函数的特性:
main函数是C语言程序的入口点。程序从main函数开始执行。
main函数的返回类型可以是int或void。在C语言中,void main和int main是一样的,但在C++中,只有int main是正确的。
如果main函数的返回类型是int,那么return语句后面通常会跟着一个整数,表示程序的退出状态。如果main函数返回void,则不需要写return语句。
在main函数中,return 0通常表示程序执行成功,而return -1或其他非零值表示程序执行失败。这个返回值可以被操作系统或其他调用此程序的程序所读取。
2.C程序代码的运行
C语言程序必须经过编译才能被CPU执行。这是因为CPU只认识二进制指令,而我们的源代码是使用文本编写的,所以必须先将其转换为二进制指令。
以下是一般C语言程序的制作流程:
(1)编写代码:通过代码编辑器将自己开发的C语言程序输入计算机的过程确实被称为编辑C程序源文件。这个编辑过程生成的文件是以文本形式存储的,并且扩展名为“.C”,这些文件就是我们所说的C代码程序文件,以ASCII码的形式存储。
(2)预处理(Preprocessing):这一步主要是对源代码进行宏替换、头文件展开、条件编译等操作。预处理器会根据源代码中的预处理指令(如#include、#define等)来生成中间代码。
(3)编译(Compilation):在预处理完成后,编译器会将中间代码转换为汇编语言。编译器在这个过程中会对代码进行语法和语义检查,确保代码符合C语言的规范。
(4)汇编(Assembly):汇编器会将编译器生成的汇编代码转换为目标机器的二进制指令,生成目标文件(.obj文件)。
(5)链接(Linking):链接器会将多个目标文件以及所需的库文件合并成一个可执行文件。链接器还会处理程序中的符号引用问题,例如函数和变量的外部引用等。
(6)运行:在DOS环境下,可以在命令行界面,你可以直接键入C程序的可执行文件名,然后按Enter键执行。在C的集成环境(如Visual Studio,Dev-C++等)下,你通常需要先编译你的C程序,生成一个可执行文件。然后,你可以在界面的菜单中找到“运行”或“执行”命令,选择它来运行你的程序。然而在Windows的资源管理器,你可以找到你的C程序的可执行文件,然后双击它。系统会自动调用默认的程序来运行这个文件。如果你没有为C程序的可执行文件设置默认的打开方式,那么可能需要通过命令行或者集成环境来运行它。
请注意,无论在哪种环境下,你的C程序必须已经正确编译并生成了可执行文件,否则你将无法运行它。
至于C语言的编译器有:
(1)GCC(GNU Compiler Collection):是一个广泛使用的开源编译器套件,支持多种编程语言,包括C语言。它是许多操作系统和开发环境的默认编译器,具有强大的优化能力和丰富的功能。
(2)Clang:是一个基于LLVM项目的C语言编译器。它被设计为具有高度可扩展性和模块化的编译器,提供了快速的编译速度和低内存占用。Clang也被广泛用于许多操作系统和开发环境中。
(3)Microsoft Visual C++:是Windows操作系统上的主要C语言编译器,由微软开发和维护。它提供了丰富的开发工具和库,使开发者能够轻松地创建Windows应用程序。
其中例举gcc编译器的处理流程如下:
1、预处理
1)宏定义展开
2)头文件展开
3)删除注释
4)条件编译
格式:gcc -E a.c -o a.i
2、编译
1)检查语法
2)转化成汇编语言
格式:gcc -S a.i -o a.s
3、汇编
1)将汇编语言转化成机器语言
格式:gcc -c a.s -o a.o
4、链接
1)将库文件链接变成可执行文件
格式:gcc a.o -o a.exe
这里暂不详细介绍各种编译器的用法。我们可以使用 Visual Studio 一键完成这些流程,只要在它里面写好源代码,直接就可以生成能够执行的程序。
三、认识C程序入口点
一般C程序常见入口函数如下:
int main(void){
return 0;
}
int _tmain(int argc,_TCHAR*argv[]){
return 0;
}
_tmain(int argc, _TCHAR* argv[])
和 main()
函数都是 C/C++ 程序的入口点,但它们在使用上有一些区别。
- 名称:
main()
是标准的 C/C++ 入口函数名称,而_tmain()
是 Microsoft Visual Studio 中的特定函数名称。 - 参数:
main()
函数接受两个参数:argc
(命令行参数的数量)和argv
(命令行参数的字符串数组)。而_tmain()
同样接受这两个参数,但_TCHAR* argv[]
中的_TCHAR
是 Unicode 字符集,可以处理多种字符编码。 - 多字节字符集:
main()
函数使用标准的 C/C++ 字符集,而_tmain()
可以处理多字节字符集(如 UTF-8)。 - 使用环境:通常情况下,使用标准编译器(如 GCC)编译 C/C++ 代码时,应该使用
main()
作为入口函数。在 Microsoft Visual Studio 中,可以使用_tmain()
来处理多字节字符集。
总之,_tmain()
和 main()
的主要区别在于字符编码处理和使用的环境。在大多数情况下,使用标准的 main()
函数是最佳选择。
四、什么是预处理
C语言的预处理是C语言源程序编译过程中的一个重要阶段,它是在编译的第一阶段进行的。预处理阶段主要处理源代码中的预处理器指令,一般以“#”开头,包括:
- 宏定义指令:如 #define 指令,预处理器会将其替换为指定的内容。
- 包含文件指令:如 #include 指令,预处理器会将其替换为指定文件的内容。
- 条件编译指令:如 #if、#ifdef、#ifndef、#else、#elif 和 #endif 指令,预处理器会根据条件判断是否进行编译。
此外,预处理阶段还会处理注释(将单行注释和多行注释替换为空)、添加行号和文件名标记(以便于后续编译阶段的错误检查和调试)等操作。
预处理阶段的结果称为“预处理后的源代码”,也称为“经过预处理后的源代码”。预处理后的源代码可以作为中间代码输入到编译的下一个阶段,即编译阶段。
编译预处理主要用于在程序正式编译前进行一些预加工操作,编译预处理共分为:宏定义,文件包含,条件编译。所有的编译预处理命令均以“#”开头。
1)宏
宏定义的作用就是在程序中某段代码的一个别名,宏定义主要为程序调试、移植等提供便利,是一个非常实用的功能。所有宏命令行都以符号“#define”开头,并且结尾不用分号,例如:
#define PI 3.14
宏定义的作用是在编译预处理时,将源程序中所有标识符替换成语句序列。宏定义分为
有参宏与无参宏。需要注意的是,宏名一般用大写字母,以便与变量名的区别,在编译预处理时宏名与字符串进行替换时,不作语法检查,只是简单的字符替换,只有在编译时才对已经展开宏名的源程序进行语法检查。宏名的有效范围是从定义位置到文件结束。如果需要终止宏定义的作用域,可以用#undef 命令,例如:
#define PI 3.14
......
#undef PI
2)无参宏与有参宏
无参宏指的是执行单一替换功能的宏定义,在使用无参宏时要注意以下两个问题:
1.宏定义时可以引用已经定义的宏名,如下所示:
#define R 2.0
#define PI 3.14
#define L 2*PI*R
2. 对程序中用双引号扩起来的字符串内的字符,不进行宏的替换操作有参宏可以让我们在定义宏时,还可以带参数扩大宏的应用范围,有参宏的格式:
#define 标识符(参数表) 字符串
它的作用是在编译预处理时,将源程序中所有标识符替换成字符串,并且将字符串中的参数用实际使用的参数替换,例如:
#define S(a,b) (a*b)/2
需要注意的是,在宏定义时,宏名和参数之间不能有空格,否则空格后面的所有字符序列都作为替换的字符串。带参数的宏展开时,只作简单的字符和参数的替换,不进行任何计算操作。
所以一般在定义宏时,字符串中的形式参数外面加一个小括号,
例如: #define L(r) 2*PI*r
如果源程序有 L(2+3),则编译预处理后变为:2*3.14159*2+3 而不是 2*3.14159*5
解决办法是:
#define L(r) 2*PI*(r)
3)文件包含
文件包含的功能是将指定的文件内容嵌入到一个源文件中,文件包含共有以下两种格式
#include <xxxx.x>//标准方式
只按照标准方式在 C语言编译器的 C 函数库头文件中查找要包含的文件。
#include"xxxx.x" //通用方式
先在源文件所在的目录中查找要包含的文件,若未能找到,则在按照标准方式查找。
五、C语言的库函数
C语言的库函数是指一些已经封装好的、可以直接调用的函数,用于完成一些常见的任务,包括字符串处理、数学计算、输入输出等,比如常见的printf
和 scanf
这两个函数用于标准输入输出。C语言的库函数是别人把一些常用到的函数编完放到一个文件里,供程序员使用。
C语言有库函数的原因主要是为了提高编程效率,减少程序员需要编写的代码量,同时提供更加丰富和强大的功能。库函数通常由C标准库提供,这些库包含了一些常用的函数,例如输入输出函数、字符串处理函数、数学函数等。使用这些库函数可以简化编程任务,减少错误,提高代码的可读性和可维护性。此外,库函数还可以提供跨平台兼容性,使得在不同的操作系统和平台上都能够使用相同的函数实现相同的功能。
六、C语言的关键字和注释
1.关键字
C语言仅有32个关键字,9种控制语句,34种运算符。我们先来认识其关键字。C语言的关键字是指C语言中预定义的保留标识符,用于表示特定的语法和语义。C语言的关键字包括:
- 标识符:用于变量、函数、结构体等实体的命名。
- 数据类型:用于定义变量和函数的返回值类型。
- 运算符:用于表示算术运算、关系运算、逻辑运算等。
- 控制结构:用于控制程序的流程,如条件语句、循环语句等。
- 函数定义:用于定义函数和函数原型。
- 预定义标识符:如#define、#include等预处理器指令。
C语言的关键字是预先定义好的,不能随意使用。这些关键字的设计是为了简化C语言的语法和语义,方便程序员的使用和理解。同时,保留关键字也是为了防止与用户定义的标识符发生冲突,保证程序的正确性和可读性。关键字如下图所示:
2.代码注释
注释的内容编译器是忽略的,不会参与程序的编译与运行,注释主要的作用是在代码中加一些说明和解释,让人对程序逻辑一目了然,这样有利于代码的阅读和维护。注释的方式有如下两种:
(1)//代码 行注释
(2)/*代码*/ 块注释
块注释是C语言标准的注释方法,行注释是从C++语言借鉴过来的。