概述
C语言是一种计算机编程语言,我们是利用代码来控制计算机的运行,从而达到某种目的,我们 就很有必要了解计算机的运行原理。
计算机组成
OS + 应用程序
计算机硬件
基本组成:
输入设备:输入数据给计算机处理,举例如:键盘,鼠标
输出设备:结果数据展示 ,举例如:显示器,打印机
外存储器:永久存放数据,容量大,但访问速率慢,举例:磁盘
内存储器:临时存放待处理的数据及运行的程序代码,访问速度快,数据是临时存放,相对来说, 容量较小,举例:内存条
处理器:
运算器:进行算术运算和逻辑判断
控制器:管理和协调计算机的其它部件
计算机运行原理
1. 计算机通过输入设备将数据加载到内存
2. CPU从内存中获取数据进行处理,并将结果数据再次放回到内存。
3. 通过输出设备将结果数据进行输出展示。
4. 如果我们需要将结果数据进行长期存储,可借助于外存储器保存。
计算机语言
机器语言(0,1,指令码) 计算机唯一可以直接运行的代码
汇编语言(符号化指令):汇编语言必须经过汇编程序转换为机器语言后计算机才能运行
高级语言:利用数学运算符及一些英文单词来描述程序指令。(C/C++/JAVA/Python)高级语言是 必须要通过编译器或者解释器转换为机器语言。
C语言版本
为了C语言健康发展下去,很多有识之士及美国国家标准协会(ANSI)于1982年成立了一个委员会以 确定C语言的标准。
C89:1989 ANSI 发布了第一个完整的C语言标准,即C89。
C90:不过人们习惯性的称为 “ANSI C”1990年ISO(国际标准化组织一字不改的采纳了 C89,官方给出的 名称为 ISO C90)
C99:1999年,C语言标准经过了一次修正和完善后,ISO发布了新版的C语言标准,简称” C99”。
C18:最新的C语言标准为 2018年6月份发布的 “C18”
C语言特点
C语言是一种强大而灵活的语言,可以用来编写任意复杂的程序。
C语言简洁、紧凑,使用方便。
C语言是可移植的。
C语言很适合结构化程序设计,因而要求用户以功能模块的方式来思考问题。
C语言可直接控制硬件 (位运算符,地址 )
生成目标代码质量高,程序执行效率高,运行速度快。
优点:
功能强大,语言灵活
C可移植性强
C语言可以直接控制硬件
C语言运行效率高
C语言具有结构化的控制语句
C语言具有丰富的数据类型和运算符
缺点:
C语言的缺点主要表现为数据的封装性弱。这一点使得C在数据的安全性上有很大的缺陷,这也是C 和C++的一大区别。
C语言的语法限制不太严格,对变量的类型约束不严格,影响程序的安全性,对数组下标越界不做 检查等。从应用的角度,C语言笔其他高级语言较难掌握。也就是说,对用C语言的人,要求对程序 设计更熟练一些。
C语言开发过程
C语言的开发分为三步:①编辑-->②编译-->③运行
1. 创建一个C语言源程序文件(.c)
2. 在源文件中由程序员编写C语言程序代码
3. 由编译器对源文件进行编译,生成可执行程序
4. 机器运行可执行程序,确认功能的正确性
C语言的编译四步骤:①预处理-->②编译-->③汇编-->链接④
C语言中3类标识符:
1.关键字(32个)
1.auto:声明自动变量,用于函数内部的局部变量
2.break:跳出当前循环
3.case:开关语句的一个分支
4.char:声明字符型变量或函数
5.const:声明只读变量,其值不能被修改
6.continue:跳出当前循环的剩余部分,开始下一次循环
7.default:开关语句中的默认选项
8.double:声明双精度浮点型变量或函数
9.do:用在循环中,表示循环体重复执行的部分
10.else:条件语句中的“否则”部分
11.enum:声明枚举类型
12.extern:声明变量或者函数是在别处定义的
13.float:生命浮点型变量或函数
14.for:一种循环语句
15.goto:无条件跳出语句
16.if:条件语句,如果指定条件为真则执行if后面的代码
17.int:声明整型变量或函数
18.long:声明长整型变量或函数
19.register:声明寄存器变量,提示编译器,该变量可能被频繁使用
20.return:子程序返回值
21.short:声明短整型变量
22.signed:生命有符号类型变量或函数
23.sizeof:计算数据类型或变量的大小
24.static:生命静态变量,表示变量生命周期直到程序结束
25.struct:生命结构体类型
26.switch:用于开关语句,选择多个选项之一执行
27.typedef:用于给数据类型定义别名
28.union:声明共用体类型
29.unsigned:生命无符号类型或函数
30.void:声明函数无返回值或者无参数
31.volatile:说明变量在程序执行中可被隐藏的更改,提示编译器对访问该变量的代码不进行优化
32.while:用于循环语句
12个预处理命令
C语言的12个预处理命令包括:#if、#ifdef、#ifndef、#else、#elif、#endif、#define、#undef、#line、#error、#pragma、#include。 这些命令都以符号#开头,每条预处理指令必须独占一行。这些命令在C语言编程中扮演着重要的角色,允许程序员在编译前对程序进行各种条件和宏定义的处理,从而影响编译过程和程序的最终行为。
#if、**#else**、**#elif** 和 #endif 用于条件编译,根据常数表达式的结果有选择地编译程序源代码的不同部分。
#define 用于定义一个标识符和一个串,在源程序中每次遇到该标识符时,都用定义的串替换它。
#undef 用于取消之前定义的宏。
#line 用于修改源文件的行号和文件名。
#error 用于强制编译程序停止编译,主要用于程序调试。
#pragma 用于为特定的编译器提供非标准的编译指令。
#include 用于读入另一个源文件,允许程序员将代码分割到多个文件中,并通过包含文件的方式将它们组合在一起。
用户标识符
C语言中的用户标识符(User Identifier)是用来命名变量、函数、标签等程序实体的名字。C语言的用户标识符必须遵循以下规则:
-只能包含字母(大写"A-Z"和小写"a-z")、数字("0-9")和下划线("_")。
-必须以字母或下划线开头。
-是大小写敏感的,即"i"和"I"被视为不同的标识符。
-不能使用C语言的关键字作为用户标识符。
用户标识符示例:
int value; // 合法
int _value; // 合法
int 2value; // 不合法,不能以数字开头
int value@; // 不合法,只能包含字母、数字和下划线
int for; // 不合法,不能使用C语言的关键字
什么是原码、反码、补码:
1. 原码
原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值。
比如:
如果是8位二进制:
[+1]原= 0000 0001
[-1]原= 1000 0001
第一位是符号位,因为第一位是符号位,所以8位二进制数的取值范围就是:(即第一位不表示值,只表示正负。)
[1111 1111 , 0111 1111] 即 [-127 , 127]
原码是人脑最容易理解和计算的表示方式。
2. 反码
反码的表示方法是:
- 正数的反码是其本身;
- 负数的反码是在其原码的基础上,符号位不变,其余各个位取反。
[+1] = [0000 0001]原= [0000 0001]反
[-1] = [1000 0001]原= [1111 1110]反
可见如果一个反码表示的是负数,人脑无法直观的看出来它的数值。通常要将其转换成原码再计算。
3. 补码
补码的表示方法是:
- 正数的补码就是其本身;
- 负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1。(也即在反码的基础上+1)
[+1] = [0000 0001]原= [0000 0001]反= [0000 0001]补
[-1] = [1000 0001]原= [1111 1110]反= [1111 1111]补
对于负数,补码表示方式也是人脑无法直观看出其数值的。通常也需要转换成原码再计算其数值。
为什么要有原码、反码、补码?
首先, 因为人脑可以知道第一位是符号位,在计算的时候我们会根据符号位,选择对真值区域的加减。但是对于计算机,加减乘数已经是最基础的运算,要设计的尽量简单,计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂!
于是人们想出了将符号位也参与运算的方法。我们知道,根据运算法则减去一个正数等于加上一个负数,即:1-1 = 1 + (-1) = 0, 所以机器可以只有加法而没有减法,这样计算机运算的设计就更简单了。
于是补码的出现,解决了0的符号问题以及0的两个编码问题:
1-1 = 1 + (-1) = [0000 0001]原+ [1000 0001]原= [0000 0001]补+ [1111 1111]补= [1 0000 0000]补=[0000 0000]补=[0000 0000]原注意:进位1不在计算机字长里。
这样0用[0000 0000]表示,而以前出现问题的-0则不存在了。而且可以用[1000 0000]表示-128:-128的由来如下:
(-1) + (-127) = [1000 0001]原+ [1111 1111]原= [1111 1111]补+ [1000 0001]补= [1000 0000]补
-1-127的结果应该是-128,在用补码运算的结果中,[1000 0000]补就是-128,但是注意因为实际上是使用以前的-0的补码来表示-128,所以-128并没有原码和反码表示。(对-128的补码表示[1000 0000]补,算出来的原码是[0000 0000]原,这是不正确的)
使用补码,不仅仅修复了0的符号以及存在两个编码的问题,而且还能够多表示一个最低数。这就是为什么8位二进制,使用原码或反码表示的范围为[-127, +127],而使用补码表示的范围为[-128, 127]。
因为机器使用补码,所以对于编程中常用到的有符号的32位int类型,可以表示范围是: [-231, 231-1] 因为第一位表示的是符号位,而使用补码表示时又可以多保存一个最小值。