一、简介
历史
语言:C 语言 ← B 语言 ← A 语言 开发环境:编辑器 + 编译器 + 调试器 系统:Linux ← UNIX
不同语言之间的区别
C/C++:可移植性强的语言,Windows 和 Linux 的接口有差异,汇编语言。 Java/Python:跨平台语言,可从 Windows 平台移植到 Linux 平台使用
学习目标
- 理解程序的执行过程
- 掌握程序调试能力
断点及调试窗口设置
内存的变化过程
在编译器行号左侧灰色部分点击出现红点(断点)。 当程序运行到断点时(上图出现黄色箭头),执行步骤截止至断点之前。此时 i 的地址内容未发生改变。 点击逐过程,程序运行下一步后,i 地址的内存发生改变,变为 i 的取值 10(十六进制表示为 0a。小端显示:低地址在前,高地址在后,实际存储内容为 00 00 00 0a)。
点击逐过程,程序执行打印 hello world 点击逐过程,程序运行 2019 版隐藏的 system("pause") ,打印【按任意键关闭此窗口】。此时程序执行 C 语言内镶嵌语言的命令 pause 。 C 语言也可嵌套其他语言,如微软的语言 BAT(微软处理脚本)、Python 等。
C/C++/Java 出错
编译错误:代码编写错误,无法编译生成 执行错误:打印结果不符合预期
编译原理解析
程序的编译过程
关于编译器解决方案与项目
- 一个解决方案可以存在多个项目;一个项目可以存在多个 .c 文件,但只能存在一个 main 函数。
- 添加已有 .c 文件:①拖拽进源文件 ②源文件右击添加现有项。
- .obj 文件(目标文件):存储及其指令(0/1 字符串)。位于项目的 Debug 文件夹中,生成失败依旧会产生 .obj 文件。
- 将需要运行的项目右击选择“设为启动项目”,调试时默认运行该项目。
- 编译器中的“生成”为增量编译,“重新生成”为重新编译。
编译与链接的区别:
- 编译:C 语言 → 汇编语言 → 机器指令。
- 链接:将函数符号替换为地址。
报错时出现 error LNK2019 为链接错误。双击报错可定位,可能是链接源的错误或链接位置的错误。
二、数据类型、运算符与表达式
学习目标
- 数据类型
- 常量与变量的差异
- 整型、浮点型、字符型的原理及应用
- scanf 函数的原理及应用
- 运算符与表达式
2.1 数据类型的分类
2.2 常量
程序运行过程中值不发生改变的量。
例:int i = 10 10 为常量 / 立即数
内存: PC 指针:程序计数器,存储一个地址值,指向当前马上要给 CPU 译码器的指令。每执行一条则向下走一条指令(每条指令不一定等长)。
译码器读取 i = 10,在栈空间开辟 4 字节内存,将 10 复制到栈空间。 变量:在栈空间上有一个存储的位置,可改变。 常量:在编译后即被放入译码器的代码段,不可改变。
64位文件可用的虚拟地址空间大小:
2
32
×
4
?
G
2^{32}×4\ G
232×4?G
2.3 变量
- 变量名:以一个名字代表一个对应的存储单元地址。不能与关键字同名。
- 从变量中取值:通过变量名找到内存中存储单元的地址,并从该存储的单元中读取数据。
- 命名规则:标识符只能由字母、数字和下划线组成,第一个字符必须为字母或下划线。
- C语言区分大小写。
- 先定义后使用。
2.4 整型数据
2.4.1 符号常量
定义:#define 变量名 常量 (末尾不加分号)。 程序中用到的常量名位置直接替换为常量内容。
例:输出为 7 3+2*2=7 其中,查看预处理效果方法:右击项目 → 属性 → 配置属性 → C/C++ / 预处理文件 → 是。重新生成后在项目 → Debug 文件夹 → 打开 main.i 文件,前几万行为头文件(.c 文件中开头带 # 行)的展开,文件末尾为预处理结果即需要查看的部分 → 查看后将“是”改回为“否”,否则之后运行报错。
作用:提高程序可读性、便于修改。
2.4.2 整型常量的不同进制表示 2 / 4 / 8 / 16
进制转换: 1个字节(byte) = 8 位(bit)。 1 KB = 1024 byte;1 MB = 1024 KB;1 GB = 1024 MB。
CPU 寻址时最小访问单元为 1 字节。 数据总线每次从内存中取 8 字节。 内存为小端模式存储。
2.4.3 补码
CPU 中的处理单元:译码器、加法器、乘法器等,不存在减法器。进行减法运算需要使用加法器与补码。
- 补码是计算机对负数的表示方式,是原码(去掉符号后字符的二进制表示)取反后加 1 的结果。
- 当最高位为 1 时表示负数。
例:2-5=2+(-5),存储 (-5) 时需要用补码表示,即需要将源码 5=0x0000 0005 取反后得 0xffff fffa,加 1 后得 0xffff fffb。加 2(有进位)后得到计算结果 0xffff fffd。 当最高位为 1 时,要得到源码才能知道 0xffff fffd 的值,即堆其取反后加 1(也可减 1 后取反或取反后加 1,结果相同)得到 3,所以其值为 3。
注:Windows 中先定义的地址较大,微软在两个变量间设置了 8 个字节的保护空间。
2.4.4 整型变量
整型变量包括 6 种类型,分别为:
- 有符号基本整型 (signed) int
- 有符号短整型 (signed) short (int)
- 有符号长整型 (signed) long (int)
- 无符号基本整型 unsigned int
- 无符号短整型 unsigned short (int)
- 无符号长整型 unsigned long (int)
注:括号表示其中的内容是可选的。
有符号基本整型与无符号基本整型的最高位所代表的意义如下: 不同整型变量表示的整型数范围如下表,超出范围会发生溢出导致计算出错。 只有整型数会产生溢出。 注:32 位的 long 长 4 字节,64 位的 long 长 8 字节。一般为 64 位(服务器)。
例:将 short 类型的 i=32767 加 1,得到 -32768。 32767 转换为二进制表示为 0111 1111 1111 1111,加 1 后得到 1000 0000 0000 0000,最高位为符号位,表示 -32768。 -32768 的原码与补码相同。 注:有符号类型输出时用%d(十进制)、%o(八进制)、%x(十六进制),无符号类型输出时用%u,具体如下:
2.5 浮点型数据(精度丢失)
2.5.1 浮点型常量
两种形式如下,常用的为指数形式: 注意:字母 e(或 E)表示 10 的幂次,e 前底数部分必须有数字,e 后的指数必须为整数。 注:形如 -.1e-3 为正确写法,表示 -0.0001。
2.5.2 浮点型变量
浮点数的数值范围与有效数字: 浮点型数据的组成(标准 4 字节浮点型 float): 指数部分表示 2 的幂次,小数部分表示输入数值的二进制表示中的小数部分。
浮点型数据按照指数形式存储:
- 系统把一个浮点型数据分成小数部分(M)和指数部分(E)并分别存放。
- 指数部分采用规范化的指数形式,指数也分正、负(符号位,用 S 表示)。
IEEE-754 浮点型变量存储标准(以 4.5=0100 0000 1001 0000 0000 0000 0000 0000 为例): S:符号位。S=1 时为负(
(
?
1
)
1
(-1)^{1}
(?1)1),S=0 时为正(
(
?
1
)
0
(-1)^{0}
(?1)0)。 E:指数部分。十进制数输入转为二进制数。存储前,指数部分都要加 127=0111 1111(IEEE-754 规定),因为需要表示负数。 M:小数部分。在二进制数小数点前保留一位(即小数点前有且只有一个 1)的前提下,小数点后的部分被存储在这里。 十进制数 4.5 分为整数部分 4 与小数部分 0.5,二进制表示为 100.1:
- 整数部分
4
=
2
2
=
100
4=2^{2}=100
4=22=100。
- 小数部分
0.5
=
2
?
1
=
0.1
0.5=2^{-1}=0.1
0.5=2?1=0.1。
使用指数形式表示为
1.001
×
2
2
1.001×2^{2}
1.001×22,由于此处为二进制数,故指数为 2 的 2 次幂。 符号位 S=0,指数部分 E=2 存储为 2+127=129=1000 0001,小数部分 M 即 001。存入结果如上表。
精度丢失:
- 数值范围
以 float 类型为例。浮点型数据指数部分占 8 位。 由于特殊数(1111 1111)与非规格数(0000 0000)的存在,指数部分最大取到 1111 1110,最小取到 0000 0001。 指数的最大表示范围到
11111110
?
01111111
=
(
2
9
?
2
)
?
127
=
254
?
127
=
127
1111 1110-0111 1111=(2^{9}-2)-127=254-127=127
11111110?01111111=(29?2)?127=254?127=127 比特。二进制浮点数的指数部分最大到
2
127
≈
1.701412
e
38
2^{127}≈1.701412e38
2127≈1.701412e38,即数值范围最大到
1
0
38
10^{38}
1038;同理,计算
2
?
126
≈
1.175494
e
?
38
2^{-126}≈1.175494e-38
2?126≈1.175494e?38 可得到数值范围最小到
1
0
?
38
10^{-38}
10?38。 - 有效数字
以 float 类型为例。小数部分 23 位,能够表示的有效数字
2
23
=
8388608
2^{23}=8388608
223=8388608,即最大到 0.8388608。因此小数部分可表示 1~6 位的所有小数(如 0.999999)与 7 位小于 0.8388608 的小数。
由于浮点型变量计算时为二进制指数部分 E 与小数部分 M 相乘(即进行移位),则有效数字在 6~7 位之间,达到逼近效果。
例 1:float f = 1.23456789e10 加 20 f 在赋值存入时即产生精度丢失。
例 2:float f == 1.456? 单步调试: f 值精确到小数点后 7 位,不等于 1.456。 正确写法:判断两个浮点数是否相等,直接用减法。 两数相减的绝对值在精度范围内。
存在部分浮点数相乘(移位)相等(如 4.5),但为保证准确性仍需直接计算。
例 3:double f =1.23456789e10 由于 double 型浮点数有效数字为 15~16 位,输出结果正确。
|