C 语言入门基础之一
大纲
编程语言发展历程
机器语言
计算机的大脑或者说心脏就是 CPU,它控制着整个计算机的运作。每种 CPU,都有自己的指令系统。这个指令系统,就是该 CPU 的机器语言。机器语言是一组由 0 和 1 系列组成的指令码,这些指令码,是 CPU 制造厂商规定出来的,然后发布出来,要求程序员遵守。要让计算机干活,就得用机器语言(二级制数)去命令它。这样的命令,不是一条两条,而是上百条。不同型号的计算机其机器语言是不相通的,也就是使用某种计算机的机器指令编制的程序,不能在另一种计算机上执行。
汇编语言
机器语言编程很令人烦恼,因此终于出现了汇编语言,就是一些标识符取代 0 与 1。汇编语言是一门人类可以比较轻松认识的编程语言。只是这门语言计算机并不认识,所以人类还不能用这门语言命令计算机做事情。所以,有一类专门的程序,既认识机器语言,又认识汇编语言,也就是编译器,将标识符换成 0 与 1,知道怎么把汇编语言翻译成机器语言。
高级语言
汇编语言和机器语言都是面向机器的,机器不同,语言也不同。既然有办法让汇编语言翻译成机器语言,难道就不能把其他更人性化的语言翻译成机器语言?1954 年,Fortran 语言出现了,其后相继出现了其他的类似语言。这批语言,使程序员摆脱了计算机硬件的限制,把主要精力放在了程序设计上,不在关注低层的计算机硬件。这类语言,称为高级语言。同样的,高级语言要被计算机执行,也需要一个翻译程序将其翻译成机器语言,这就是编译程序,简称 “编译器”。这类高级语言解决问题的方法是分析出解决问题所需要的步骤,把程序看作是数据被加工的过程。基于这类方法的程序设计语言,成为了面向过程的语言。
语言的层次
语言的进化史
为什么要学习 C 语言
C 语言的特点
优点:
- 代码量小
- 功能强大
- 编程自由
- 执行速度快
缺点:
- 可移植性较差
- 对平台库依赖较多
- 写代码实现周期长
- 过于自由,经验不足易出错
学习 C 语言理由
C 语言的应用领域
C 语言的应用极其广泛,从网站后台,到底层操作系统,从多媒体应用到大型网络游戏,均可使用 C 语言来开发:
- C 语言可以写网站后台程序
- C 语言可以专门针对某个领域写出功能强大的程序库
- C 语言可以写出大型游戏的引擎
- C 语言可以写出另一个语言来,例如:PHP 纯 C 语言开发的
- C 语言可以写操作系统和驱动程序,并且一般只能用 C 语言编写
- 任何设备只要配置了微处理器,就都支持 C 语言。从微波炉到手机,都是由 C 语言技术来推动的
- 详见:各类语言的应用领域图解分析
第一个 C 语言程序
编写代码
1 |
|
编译代码
- GCC 编译命令常用选项说明
选项 | 含义 |
---|---|
-o | 指定生成的输出文件名 |
-E | 只进行预处理 |
-S | 只进行预处理和编译 |
-c | 只进行预处理、编译和汇编 |
- 编译代码,生成可以执行文件
1 | $ gcc hello.c -o hello |
运行代码
- 运行可执行文件
1 | $ ./hello |
代码分析
#include
头文件包含:#include
的意思是头文件包含,#include <stdio.h>
表示包含stdio.h
这个头文件- 使用 C 语言库函数时,需要提前包含库函数对应的头文件,如这里使用了
printf()
函数,则需要包含stdio.h
头文件
#include <>
与#include ""
的区别:<>
表示编译器直接按系统指定的目录(/usr/include
)检索头文件""
表示系统先在""
指定的路径(没写路径则默认使用当前路径)查找头文件,如果找不到,再按系统指定的目录检索
main()
函数- 一个完整的 C 语言程序,是由一个、且只能有一个
main()
函数(又称主函数,必须有)和若干个其他函数结合而成(可选) main()
函数是 C 语言程序的入口,程序是从main()
函数开始执行的
- 一个完整的 C 语言程序,是由一个、且只能有一个
printf()
函数printf()
是 C 语言库函数,功能是向标准输出设备输出一个字符串printf()
函数在stdio.h
头文件里定义\n
表示回车换行
return
语句return
代表函数执行完毕- 如果
main()
函数定义的时候前面是int
,那么return
后面就需要写一个整数 - 如果
main()
函数定义的时候前面是void
,那么return
后面什么也不需要写 - 在
main()
函数中return 0
代表程序执行成功,return -1
代表程序执行失败 int main()
和void main()
在 C 语言中都是支持的,但 C++ 只支持int main()
这种定义方式
system 函数
system 函数的定义
1 | 头文件:#include <stdlib.h> |
system 函数的调用
1 |
|
system 函数的返回值
在 Linux 和 Windows 系统下分别调用 system()
函数,若调用成功返回值是不一样的,若调动失败返回值一般为 -1
。C 语言所有的库函数调用,只能保证语法是一致的,但不能保证执行结果是一致的;同样的库函数在不同的操作系统下执行结果可能是一样的,也可能是不一样的。Linux 的发展离不开 POSIX 标准,只要符合这个标准的函数,在不同的系统下执行的结果就可以一致。Unix 和 Linux 很多库函数都是支持 POSIX 标准的,但 Windows 支持的比较差。如果将 Unix 代码移植到 Linux 一般代价很小,如果把 Windows 代码移植到 Unix 或者 Linux 就比较麻烦。
C 语言的编译过程
C 语言的编译步骤
C 语言编译成可执行程序需要经过以下 4 个步骤,详见 编译流程图。
预处理
:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法编译
:检查语法,将预处理后文件编译生成汇编文件汇编
:将汇编文件生成目标文件(二进制文件)链接
:C 语言编写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去
GCC 的编译过程
GCC 的编译步骤
步骤 | 命令 |
---|---|
1. 预处理 | gcc -E hello.c -o hello.i |
2. 编译到汇编代码 | gcc -S hello.c -o hello.s |
3. 汇编到目标代码(二进制文件) | gcc -c hello.s -o hello.o |
4. 链接,生成可执行文件 | gcc hello.o -o hello |
值得一提的是,以上四个步骤,可以合成一个步骤,直接编译链接成可执行目标文件,命令是 gcc hello.c -o hello
文件后缀的不同含义
文件后缀 | 含义 |
---|---|
.c | C 语言文件 |
.i | 预处理后的 C 语言文件 |
.s | 编译后的汇编文件 |
.o | 编译后的目标文件 |
查找程序所依赖的动态库
1 | # GCC编译 |
在 Windows 系统里,可以使用 Dependency Walker 工具查看程序所依赖的动态库(DLL),如下图所示:
VS 中 C 语言嵌套汇编代码
在 Visual Studio 中,由于下述代码使用了 eax
寄存器,因此程序需要运行在 32 位(x86)的平台。
1 |
|