Loading... # 数据类型 # 基本数据类型 **short、int、long、char、float、double 这六个关键字代表C 语言里的六种基本数据类型。** ## **C语言中,数据类型可分为**: 1. **基本数据类型** 2. **构造数据类型** 3. **指针类型** 4. **空类型** ```mindmap - C数据类型 - 基本类型 - 数值类型 - 整型 - 短整型 short - 整形 int - 长整型 long - 浮点型 - 单精度浮点型 float - 双精度浮点型 double - 字符类型 char - 构造类型 - 数组 - 结构体 struct - 共用体 union - 枚举类型 enum - 指针类型 - 空类型 ``` **数据类型分类** 最常用的**整型, 实型与字符型**(char,int,float,double): **整型数据**是指不带小数的数字(**int**、**short int**、**long int** 、**unsigned int,** **unsigned short int**、**unsigned long int**): **注:** - `int` `short int` `long int`是**根据编译环境的不同,所取范围不同。** - 而其中`short int`和`long int`至少是表中所写范围, 但是`int`在表中是以16位编译环境写的取值范围。 - 另外 c语言`int`的取值范围在于他占用的字节数 ,不同的编译器,规定是不一样。 - ANSI标准定义`int`是占2个字节,TC是按ANSI标准的,它的`int`是占2个字节的。但是在VC里,一个`int`是占4个字节的。 | | 16位编译器 | 32位编译器 | 64位编译器 | | --------------- | ---------- | ---------- | ---------- | | char | 1 | 1 | 1 | | void*(指针变量) | 2 | 4 | 8 | | short int | 2 | 2 | 2 | | unsigned int | 2 | 4 | 4 | | int | 2 | 4 | 4 | | float | 4 | 4 | 4 | | double | 8 | 8 | 8 | | long | 4 | 4 | 8 | | unsigned long | 4 | 4 | 8 | | long long | 8 | 8 | 8 | ## 关键字 下表列出了 C 中的保留字。这些保留字不能作为常量名、变量名或其他标识符名称。 | 关键字 | 说明 | | -------- | ------------------------------------------------------------ | | auto | 声明自动变量 | | break | 跳出当前循环 | | case | 开关语句分支 | | char | 声明字符型变量或函数返回值类型 | | const | 定义常量,如果一个变量被 const 修饰,那么它的值就不能再被改变 | | continue | 结束当前循环,开始下一轮循环 | | default | 开关语句中的"其它"分支 | | do | 循环语句的循环体 | | double | 声明双精度浮点型变量或函数返回值类型 | | else | 条件语句否定分支(与 if 连用) | | enum | 声明枚举类型 | | extern | 声明变量或函数是在其它文件或本文件的其他位置定义 | | float | 声明浮点型变量或函数返回值类型 | | for | 一种循环语句 | | goto | 无条件跳转语句 | | if | 条件语句 | | int | 声明整型变量或函数 | | long | 声明长整型变量或函数返回值类型 | | register | 声明寄存器变量 | | return | 子程序返回语句(可以带参数,也可不带参数) | | short | 声明短整型变量或函数 | | signed | 声明有符号类型变量或函数 | | sizeof | 计算数据类型或变量长度(即所占字节数) | | static | 声明静态变量 | | struct | 声明结构体类型 | | switch | 用于开关语句 | | typedef | 用以给数据类型取别名 | | unsigned | 声明无符号类型变量或函数 | | union | 声明共用体类型 | | void | 声明函数无返回值或无参数,声明无类型指针 | | volatile | 说明变量在程序执行中可被隐含地改变 | | while | 循环语句的循环条件 | # 变量与常量 C 中有两种类型的表达式: - **左值(lvalue)**:指向内存位置的表达式被称为左值(lvalue)表达式,即:命名标识符。左值可以出现在赋值号的左边或右边。 - **右值(rvalue)**:指的是存储在内存中某些地址的数值,即:实际的数据值。右值是不能对其进行赋值的表达式,也就是说,右值可以出现在赋值号的右边,但不能出现在赋值号的左边。 变量和常量是左值,因此可以出现在赋值号的左边。数值型的字面值是右值,因此不能被赋值,不能出现在赋值号的左边。 # 变量 变量其实就是一个有名字的数据项。或者说,变量表示一个具有名字的,具有特定属性的存储空间。在程序运行过程中该存储空间内的数据值可以被改变。习惯上,变量名使用小写字母表示,而大写字母常用于字符常量或自定义数据类型名。 变量具有下列三个要素: 1. **变量名**:内存入口地址 2. **数据类型**:决定了内存空间的大小 3. **数据值**:储存在内存空间中的数值 ## 变量的类型 变量名由字母、数字和下划线字符组成。它必须以字母或下划线开头,大小写敏感。有以下几种基本的变量类型: ![](https://wmicheng.top/images/Cimages/C/02.png) 此外,C 语言也允许定义各种其他类型的变量,比如**枚举**、**指针**、**数组**、**结构**、**共用体**等等。 ## 变量的声明 变量声明,向编译器保证变量以指定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。**变量声明只在编译时有它的意义**,在程序连接时编译器需要实际的变量声明,当程序使用了一个没有被声明的变量名时候就会出现编译错误。 若只是声明定义了变量的数据类型,但却没有为变量赋予数据值,则变量所分配的内存单元中还保留着自上一次内存单元存储的旧数据。 > **变量的声明有两种情况**: 1. **一种是需要建立存储空间的**。例如:`int a` 在声明的时候就已经建立了存储空间。 2. **另一种是不需要建立存储空间的**,通过使用 extern 关键字声明了变量名而不定义它。 例如:`extern int a` 其中变量 a 可以在别的文件中进行定义的。 ```c extern int i; //声明,但不定义 int i; //声明,也是定义 ``` ## 变量的定义 变量定义,就是告诉编译器在**何处创建**变量的存储,以及**如何创建**变量的存储。本质就是确定了内存地址的起始地址和内存空间大小。 **不带初始化的定义**:带有静态存储持续时间的变量会被隐式初始化为 NULL(所有字节的值都是 0),其他所有变量的初始值是未定义的。 ```c int i, j, k; char c, ch; float f, salary; double d; ``` ## 变量的初始化与赋值 **同时完成变量的定义和初始化**:把数值填充到内存空间。 ```c extern int d = 3, f = 5; // d 和 f 的声明与初始化 int d = 3, f = 5; // 定义并初始化 d 和 f byte z = 22; // 定义并初始化 z char x = 'x'; // 变量 x 的值为 'x' ``` **变量的初始化本质就是与变量定义同时进行的第一次赋值**,此外的都称之为赋值。 ```c #include <stdio.h> // 定义全局变量 int x; int y; int addtwonum(){ // 声明使用全局变量 extern int x; extern int y; // 为全局变量进行赋值 x = 1; y = 1; return x + y; } int main(){ int result; result = addtwonum(); printf("result : %d", result); return 0; } ``` ## 变量的命名规则 1. **命名应当直观且可以拼读,可望文知意,便于记忆和阅读**。 标识符最好采用英文单词或其组合,不允许使用拼音。程序中的英文单词一般不要太复杂,用词应当准确。 2. **命名的长度应当符合“min-length && max-information”原则**。 C 是一种简洁的语言, 命名也应该是简洁的。例如变量名MaxVal 就比MaxValueUntilOverflow 好用。标识符的长度一般不要过长,较长的单词可通过去掉“元音”形成缩写。 3. **当标识符由多个词组成时,每个词的第一个字母大写,其余全部小写**。 比如: `int CurrentVal;` 这样的名字看起来比较清晰,远比一长串字符好得多。 4. 尽**量避免名字中出现数字编号,如Value1,Value2 等,除非逻辑上的确需要编号**。比如驱动开发时为管脚命名,非编号名字反而不好。 初学者总是喜欢用带编号的变量名或函数名,这样子看上去很简单方便,但其实是一颗颗定时炸弹。这个习惯初学者一定要改过来。 5. **对在多个文件之间共同使用的全局变量或函数要加范围限定符**(建议使用模块名(缩写)作为范围限定符),如 GUI_ ,etc **注意,英文词尽量不缩写,特别是非常用专业名词,如果有缩写,在同一系统中对同一单词必须使用相同的表示法,并且注明其意思。** # 常量 常量就像是常规的变量,常量是固定值,在程序执行期间不会改变,通常使用大写字母标识。 ![](https://wmicheng.top/images/Cimages/C/03.png) - **整型常量**:即整数 - **浮点型常量**:又称为实型常量,即小数,可使用小数或指数形式来表示 - **字符型常量**:即符号,用单引号括起来的一个字符,具有一般字符和转义字符两种类型 - **字符串常量**:即用双引号括起来的多个字符组成的字符序列 - **符号常量**:即对常量进行命名,所以字符常量即是常量名,使用 const 关键字或 #define 预处理器指令来定义 ## 整型常量 整数常量可以是十进制、八进制或十六进制的常量,通过前缀来确定。整数常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意。 ```c 85 /* 十进制 */ 0213 /* 八进制 */ 0x4b /* 十六进制 */ 30 /* 整数 */ 30u /* 无符号整数 */ 30l /* 长整数 */ 30ul /* 无符号长整数 */ ``` ## 浮点型常量 浮点型常量,又称实型常量,具有以下两种表示方式: - 小数形式:带小数点的常数。例如:21.290000。 - 指数形式(科学计数法):由数符尾数(整数或小数)、阶码标志(E 或 e)、阶符和整数阶码组成的常数。例如:2.129000e+001。 NOTE: - 浮点型常量默认为双精度 double 类型。 - 若浮点型常量以 F 或 f 结尾,表示该浮点型常量为单精度 float 类型常量。 - 若浮点型常量以 l 或 L 结尾,表示该浮点型常量为 long double 类型常量。 ```c 3.14159 /* 合法的 */ 314159E-5L /* 合法的 */ 510E /* 非法的:不完整的指数 */ 210f /* 非法的:没有小数或指数 */ .e55 /* 非法的:缺少整数或分数 */ ``` ## 字符型常量 字符型(Char)常量:用**单引号**括起来,具有两种类型: - 一般字符常量:一个用单引号 ’ ’ 括起来的字符。 - 转义字符常量:一个用单引号 ’ ’ 括起的,并以反斜杠 ‘’ 开头的字符,用于表示具有特殊功能的字符。 字符型常量占用 1Byte 内存空间,以 ASCII 码形式(即整型)存储。 因此,字符型数据对象和整型数据对象是可相互转换的。 **常见字符的ASCII码值如下**: SCII值为8、9、10 和13 分别转换为**退格**、**制表**、**换行**和**回车**字符。 - **退格**的ASCII码值为**8**; - **制表**的ASCII码值为**9**; - **换行**的ASCII码值为**10**; - **回车**的ASCII码值为**13**; - **空格**的ASCII码值为**32**; - **数字0**到**9**的ASCII码值分别为**48**~**57**; - **大写字母**“**A**”到“**Z**”的ASCII码值分别为**65**~**90**; - **小写字母**“**a**”到“**z**”的ASCII码值分别为**97**~**122**。 **转义字符的初衷是用于 ASCII 编码,所以它的取值范围有限**: - **八进制**形式的转义字符最多后跟三个数字,也即`\ddd`,最大取值是`\177`; - **十六进制**形式的转义字符最多后跟两个数字,也即`\xdd`,最大取值是`\7f`。 ### **转义序列表** | 转义字符 | 意义 | ASCII码值(十进制) | | -------- | ---------------------------------------- | ------------------- | | \a | 响铃(BEL) | 007 | | \b | 退格(BS) ,将当前位置移到前一列 | 008 | | \f | 换页(FF),将当前位置移到下页开头 | 012 | | \n | 换行(LF) ,将当前位置移到下一行开头 | 010 | | \r | 回车(CR) ,将当前位置移到本行开头 | 013 | | \t | 水平制表(HT) | 009 | | \v | 垂直制表(VT) | 011 | | \' | 单引号 | 039 | | \" | 双引号 | 034 | | \\ | 反斜杠 | 092 | | \ddd | 八进制形式的转义字符;最多后跟三个数字 | 127 | | \xdd | 十六进制形式的转义字符;最多后跟两个数字 | 127 | ## 字符串常量 字符串(String)常量:一个用双引号 " " 括起来的字符串,可以保存多个字符(e.g. “abc”)。 字符串常量中的字符序列在内存中连续存储,并在最后面加上转义字符 ‘\0’ 作为字符串结束标志,字符 ‘\0’ 占用 1Byte 内存空间。 例如:字符串 “HELLO” 在内存实际占据 6Bytes,实际字符存放顺序为 ‘H’、‘E’、‘L’、‘L’、‘O’、’\0’。 下面的实例显示了一些字符串常量。下面这三种形式所显示的字符串是相同的。 ```c "hello, dear" "hello, \ dear" "hello, " "d" "ear" ``` ## 符号常量 使用符号来作为常量的标识,所以也叫常量名。 符号常量具有两种定义方式: ### define 使用 `#define` 预处理器定指令义常量的形式,**不需要声明常量的数据类型**:`#define 符号常量名 常量表达式;`。 ```c #include <stdio.h> #define LENGTH 10 #define WIDTH 5 #define NEWLINE '\n' int main() { int area; area = LENGTH * WIDTH; printf("value of area : %d", area); printf("%c", NEWLINE); return 0; } ``` #### **#define使用中的常见问题解析** ##### **1. 简单宏定义使用中出现的问题** > 例1: ```c #define N 2+2 void main() { int a=N*N; printf(“%d”,a); } ``` ```c 上述问题的计算为 2+2*2+2,并不是(2+2)*(2+2) ``` **(1) 问题解析:** 如1节所述,宏展开是在预处理阶段完成的,这个阶段把替换文本只是看作一个字符串,并不会有任何的计算发生,在展开时是在宏N出现的地方 只是简单地使用串2+2来代替N,并不会增添任何的符号,所以对该程序展开后的结果是a=2+2*2+2,计算后=8,这就是宏替换的实质,如何写程序才能完成结果为16的运算 **(2)解决办法:** ```c //将宏定义写成如下形式 #define N (2+2) //这样就可替换成(2+2)*(2+2)=16 ``` ##### **2 带参数的宏定义出现的问题** (非常重要!) 在带参数的宏定义的使用中,极易引起误解。例如我们需要做个宏替换能求任何数的平方,这就需要使用参数,以便在程序中用实际参数来替换宏定义中的参数。一般容易写成如下形式: ```c #define area(x) x*x /*这在使用中是很容易出现问题的,看如下的程序*/ void main() { int y = area(2+2); printf(“%d”,y); } ``` 按理说给的参数是`2+2`,所得的结果应该为`4*4=16`,但是错了,因为该程序的实际结果为8,仍然是没能遵循纯粹的简单替换的规则,又是先计算再替换 了。 在这道程序里,2+2即为area宏中的参数,应该由它来替换宏定义中的x,即替换成`2+2*2+2=8`了。那如果遵循(1)中的解决办法,把2+2 括起来,即把宏体中的x括起来,是否可以呢?`#define area(x) (x)*(x)`,对于`area(2+2)`,替换为`(2+2)*(2+2)=16`,**可以解决**。 但是对于`area(2+2)/area(2+2)`又会怎么样呢,当一看到这道题马上给出结果,因为分子分母一样,又错了,还是忘了遵循先替换再计算的规则了,这道题替换后会变为 `(2+2)*(2+2)/(2+2)*(2+2)`即`4*4/4*4`按照乘除运算规则,结果为`16/4*4=4*4=16`,**解决方法是在整个宏体上再加一个括号**,即`#define area(x) ((x)*(x))`,不能觉得这没必要,没有它就出错 如果是自己编程使用宏替换,则在使用简单宏定义时,当字符串中**不只一个符号**时,**加上括号表现出优先级**,如果是带参数的宏定义,则要给宏体中的**每个参数加上括号**,**并在整个宏体上再加一个括号**。 **计算 “乘法” 的宏** ```c #include <stdio.h> #define MUL(a) ((a) * (a) * (a))fffffff int main(int argc, char *argv[]) { int i = 10; int sum = MUL(i); printf("MUL(%d) = %d\n", i, sum); return 0; } ``` 上面程序的这种做法对于非负数而言那就是没有问题的,比如,程序中的 变量 i=10 > 调用宏得到的数据如下: ```c MUL(10)=1000 ``` 但是如何变量的数值是自加或者自减的操作的话,结果就不一样了 ##### 说明: 1. 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含**任何字符**,可以是**常数**,也可以是**表达式**,**预处理程序对它不作任何检查**。如有错误,只能在编译已被宏展开后的源程序时发现。 2. 宏定义不是说明或语句,在**行末不必加分号**,如加上分号则连分号也一起置换。 3. 宏定义必须**写在函数之外**,其作用域为宏定义命令起到源程序结束。如要**终止其作用域可使用# undef命令**。 4. 宏名在源程序中**若用引号**括起来,则预处理程序**不对**其作宏**代换。** 5. **宏定义允许嵌套,**在宏定义的字符串中可以**使用已经定义的宏名。在宏展开时由预处理程序层层代换。** 6. **习惯上宏名用大写字母**表示,以便于与变量区别。但也**允许用小写字母。** 7. 可用宏定义表**示数据类型,**使书写方便**。如:#define STU struct stu** 在程序中可用STU作变量说明:**STU body[5],\*p;** 8. **对“输出格式”作宏定义**,可以减少书写麻烦**。** ### const 使用 `const` 关键字**声明指定类型**的常量:`const 数据类型 符号常量名 = 常量表达式;`。 ```c #include <stdio.h> int main() { const int LENGTH = 10; const int WIDTH = 5; const char NEWLINE = '\n'; int area; area = LENGTH * WIDTH; printf("value of area : %d", area); printf("%c", NEWLINE); return 0; } ``` **NOTE**: - 使用 const 方式定义符号常量时,必须初始化符号常量 - 在程序运行过程中,不能修改符号常量的数据值 - 符号常量名一般用大写字母表示 - 符号常量定义中的常量表达式不能含有变量或函数 #### 两者的区别 **(1) 编译器处理方式不同** - \#define 宏是在预处理阶段展开。 - const 常量是编译运行阶段使用。 **(2) 类型和安全检查不同** - \#define 宏没有类型,不做任何类型检查,仅仅是展开。 - const 常量有具体的类型,在编译阶段会执行类型检查。 **(3) 存储方式不同** - \#define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。(宏定义不分配内存,变量定义分配内存。) - const常量会在内存中分配(可以是堆中也可以是栈中)。 **(4) const 可以节省空间,避免不必要的内存分配。 例如:** ```c #define NUM 3.14159 //常量宏 const doulbe Num = 3.14159; //此时并未将Pi放入ROM中 ...... double i = Num; //此时为Pi分配内存,以后不再分配! double I= NUM; //编译期间进行宏替换,分配内存 double j = Num; //没有内存分配 double J = NUM; //再进行宏替换,又一次分配内存! ``` const 定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象 #define 一样给出的是立即数,所以,const 定义的常量在程序运行过程中只有一份拷贝(因为是全局的只读变量,存在静态区),而 #define 定义的常量在内存中有若干个拷贝。 **(5) 提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。** **(6) 宏替换只作替换,不做计算,不做表达式求解;** **(7)`define`可以定义函数,`const`不可以**。 # 作用域 所谓作用域(Scope),就是变量的有效范围。C 语言中所有的变量都有自己的作用域,决定变量作用域的是变量的定义位置。 - **局部变量(Local Variable)**:定义在函数内部的变量称为局部变量,包括函数形参变量。实参给形参传值的过程也就是给局部变量赋值的过程。 - **全局变量(Global Variable)**:它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h 文件。 注:局部变量和全局变量的名称可以相同,但是在函数内,如果两个名字相同,会优先使用局部变量值,全局变量不会被使用。 全局变量与局部变量在内存中的区别: - 全局变量保存在内存的全局存储区中,占用静态的存储单元; - 局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。 - 当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动对其初始化。 | 数据类型 | 初始化默认值 | | -------- | ------------ | | int | 0 | | char | '\0' | | float | 0.0\|\|0 | | double | 0.0\|\|0 | | pointer | NULL | 注:正确地初始化变量是一个良好的编程习惯。 ```c float f1=0.0; //常用 float f2=0; //不常用 ``` 如果需要在一个源文件中引用另外一个源文件中定义的变量,我们只需在引用的源文件中将变量加上 extern 关键字的声明即可。如下例: > - `addtwonum.c` ```c #include <stdio.h> extern int x; extern int y; int addtwonum(){ return x + y; } ``` > - `main.c` ```c #include <stdio.h> int x=1; int y=1; int addtwonum(); int main(){ int result; result = addtwonum(); printf("result : %d", result); return 0; } ``` **运行**: ``` result : 2 ``` 注意,因为 C 语言代码是从前往后依次执行的,所以全局变量通常位于源文件的顶部。 ```c int a, b; //全局变量 void func1(){ //TODO: } float x,y; //全局变量 int func2(){ //TODO: } int main(){ //TODO: return 0; } ``` a、b、x、y 都是在函数外部定义的全局变量。由于 x、y 定义在函数 func1() 之后,所以在 func1() 内无效;而 a、b 定义在源程序的开头,所以在 func1()、func2() 和 main() 内都有效。 # 存储类 存储类定义了 C 程序中的变量/函数的作用域和生命周期,通过特殊的修饰符(关键字)来进行修饰不同的变量/函数,使得他们具有灵活的作用域。下面列出 C 程序中可用的存储类: - auto - register - static - extern ## auto 修饰符 auto 存储类是所有局部变量默认的存储类。auto 只能用在函数内,即 auto 只能用于修饰局部变量。 下述实例定义了两个具有相同存储类的变量: ```c { int mount; auto int month; } ``` ## register 修饰符 register 存储类用于定义存储在寄存器中而不是内存中的局部变量。这意味着变量的最大 Size 等于寄存器的 Size,且不能对它应用一元运算符 ‘&’ (因为它没有内存空间)。 寄存器只用于需要快速访问的变量,比如:计数器。还应注意的是,使用了 register 修饰符进行修复并不意味着变量将被存储在寄存器中,它意味着变量**可能**存储在寄存器中,这取决于硬件和实现的限制。 ```c { register int miles; } ``` ## static 修饰符 被 static 修饰的变量和常量被称为 静态变量 或 静态常量。 - 用于修饰局部变量时:编译器在程序的生命周期内保持局部变量的存在,不会在每次进入和离开函数的时候对局部变量进行重新的创建和销毁(重新赋值)。因此,使用 static 修饰局部变量可以在函数调用之间保持住局部变量的值不被重置。 - 用于修饰全局变量时:会使变量的作用域限制在声明它的源文件内,而不再是整个程序。 ```c #include <stdio.h> /* 函数声明 */ void func1(void); static int count=10; /* 全局变量 - static 是默认的 */ int main() { while (count--) { func1(); } return 0; } void func1(void) { /* 'thingy' 是 'func1' 的局部变量 - 只初始化一次 * 每次调用函数 'func1' 'thingy' 值不会被重置。 */ static int thingy=5; thingy++; printf(" thingy 为 %d , count 为 %d\n", thingy, count); } ``` 运行: ```c thingy 6, count 9 thingy 7, count 8 thingy 8, count 7 thingy 9, count 6 thingy 10, count 5 thingy 11, count 4 thingy 12, count 3 thingy 13, count 2 thingy 14, count 1 thingy 15, count 0 ``` 可见,静态变量 thingy 不会在每次函数调用时重置。 ## extern 修饰符 extern 存储类用于提供一个全局变量/函数的引用。全局变量/函数的作用域是整个程序,当你在一个源文件中想引用另外一些源文件中定义的全局变量/函数时,你可以在该源文件中使用 extern 修饰符,修饰一个全局变量/函数,而且不需要进行初始化(因为该全局变量实际上在另一个源文件中已经完成了初始化)。 简而言之,extern 修饰符就是用与在一个文件中,对另外一个完全中的全局变量或函数进行声明(但不定义),向编译器保证该变量/函数的存在(即便变量/函数的定义并不在本文件中)。 > - `main.c` ```c #include <stdio.h> int count ; extern void write_extern(); int main() { count = 5; write_extern(); } ``` > - `support.c` ```c #include <stdio.h> extern int count; void write_extern(void) { printf("count is %d\n", count); } ``` # ASCII 码表 | 二进制 | 十进制 | 十六进制 | 字符/缩写 | 解释 | | -------- | ------ | -------- | --------------------------------------------------------- | ---------------------------------- | | 00000000 | 0 | 00 | NUL (NULL) | 空字符 | | 00000001 | 1 | 01 | SOH (Start Of Headling) | 标题开始 | | 00000010 | 2 | 02 | STX (Start Of Text) | 正文开始 | | 00000011 | 3 | 03 | ETX (End Of Text) | 正文结束 | | 00000100 | 4 | 04 | EOT (End Of Transmission) | 传输结束 | | 00000101 | 5 | 05 | ENQ (Enquiry) | 请求 | | 00000110 | 6 | 06 | ACK (Acknowledge) | 回应/响应/收到通知 | | 00000111 | 7 | 07 | BEL (Bell) | 响铃 | | 00001000 | 8 | 08 | BS (Backspace) | 退格 | | 00001001 | 9 | 09 | HT (Horizontal Tab) | 水平制表符 | | 00001010 | 10 | 0A | LF/NL(Line Feed/New Line) | 换行键 | | 00001011 | 11 | 0B | VT (Vertical Tab) | 垂直制表符 | | 00001100 | 12 | 0C | FF/NP (Form Feed/New Page) | 换页键 | | 00001101 | 13 | 0D | CR (Carriage Return) | 回车键 | | 00001110 | 14 | 0E | SO (Shift Out) | 不用切换 | | 00001111 | 15 | 0F | SI (Shift In) | 启用切换 | | 00010000 | 16 | 10 | DLE (Data Link Escape) | 数据链路转义 | | 00010001 | 17 | 11 | DC1/XON (Device Control 1/Transmission On) | 设备控制1/传输开始 | | 00010010 | 18 | 12 | DC2 (Device Control 2) | 设备控制2 | | 00010011 | 19 | 13 | DC3/XOFF (Device Control 3/Transmission Off) | 设备控制3/传输中断 | | 00010100 | 20 | 14 | DC4 (Device Control 4) | 设备控制4 | | 00010101 | 21 | 15 | NAK (Negative Acknowledge) | 无响应/非正常响应/拒绝接收 | | 00010110 | 22 | 16 | SYN (Synchronous Idle) | 同步空闲 | | 00010111 | 23 | 17 | ETB (End of Transmission Block) | 传输块结束/块传输终止 | | 00011000 | 24 | 18 | CAN (Cancel) | 取消 | | 00011001 | 25 | 19 | EM (End of Medium) | 已到介质末端/介质存储已满/介质中断 | | 00011010 | 26 | 1A | SUB (Substitute) | 替补/替换 | | 00011011 | 27 | 1B | ESC (Escape) | 逃离/取消 | | 00011100 | 28 | 1C | FS (File Separator) | 文件分割符 | | 00011101 | 29 | 1D | GS (Group Separator) | 组分隔符/分组符 | | 00011110 | 30 | 1E | RS (Record Separator) | 记录分离符 | | 00011111 | 31 | 1F | US (Unit Separator) | 单元分隔符 | | 00100000 | 32 | 20 | (Space) | 空格 | | 00100001 | 33 | 21 | ! | | | 00100010 | 34 | 22 | " | | | 00100011 | 35 | 23 | # | | | 00100100 | 36 | 24 | $ | | | 00100101 | 37 | 25 | % | | | 00100110 | 38 | 26 | & | | | 00100111 | 39 | 27 | ' | | | 00101000 | 40 | 28 | ( | | | 00101001 | 41 | 29 | ) | | | 00101010 | 42 | 2A | * | | | 00101011 | 43 | 2B | + | | | 00101100 | 44 | 2C | , | | | 00101101 | 45 | 2D | - | | | 00101110 | 46 | 2E | . | | | 00101111 | 47 | 2F | / | | | 00110000 | 48 | 30 | 0 | | | 00110001 | 49 | 31 | 1 | | | 00110010 | 50 | 32 | 2 | | | 00110011 | 51 | 33 | 3 | | | 00110100 | 52 | 34 | 4 | | | 00110101 | 53 | 35 | 5 | | | 00110110 | 54 | 36 | 6 | | | 00110111 | 55 | 37 | 7 | | | 00111000 | 56 | 38 | 8 | | | 00111001 | 57 | 39 | 9 | | | 00111010 | 58 | 3A | : | | | 00111011 | 59 | 3B | ; | | | 00111100 | 60 | 3C | < | | | 00111101 | 61 | 3D | = | | | 00111110 | 62 | 3E | > | | | 00111111 | 63 | 3F | ? | | | 01000000 | 64 | 40 | @ | | | 01000001 | 65 | 41 | A | | | 01000010 | 66 | 42 | B | | | 01000011 | 67 | 43 | C | | | 01000100 | 68 | 44 | D | | | 01000101 | 69 | 45 | E | | | 01000110 | 70 | 46 | F | | | 01000111 | 71 | 47 | G | | | 01001000 | 72 | 48 | H | | | 01001001 | 73 | 49 | I | | | 01001010 | 74 | 4A | J | | | 01001011 | 75 | 4B | K | | | 01001100 | 76 | 4C | L | | | 01001101 | 77 | 4D | M | | | 01001110 | 78 | 4E | N | | | 01001111 | 79 | 4F | O | | | 01010000 | 80 | 50 | P | | | 01010001 | 81 | 51 | Q | | | 01010010 | 82 | 52 | R | | | 01010011 | 83 | 53 | S | | | 01010100 | 84 | 54 | T | | | 01010101 | 85 | 55 | U | | | 01010110 | 86 | 56 | V | | | 01010111 | 87 | 57 | W | | | 01011000 | 88 | 58 | X | | | 01011001 | 89 | 59 | Y | | | 01011010 | 90 | 5A | Z | | | 01011011 | 91 | 5B | [ | | | 01011100 | 92 | 5C | \ | | | 01011101 | 93 | 5D | ] | | | 01011110 | 94 | 5E | ^ | | | 01011111 | 95 | 5F | _ | | | 01100000 | 96 | 60 | ` | | | 01100001 | 97 | 61 | a | | | 01100010 | 98 | 62 | b | | | 01100011 | 99 | 63 | c | | | 01100100 | 100 | 64 | d | | | 01100101 | 101 | 65 | e | | | 01100110 | 102 | 66 | f | | | 01100111 | 103 | 67 | g | | | 01101000 | 104 | 68 | h | | | 01101001 | 105 | 69 | i | | | 01101010 | 106 | 6A | j | | | 01101011 | 107 | 6B | k | | | 01101100 | 108 | 6C | l | | | 01101101 | 109 | 6D | m | | | 01101110 | 110 | 6E | n | | | 01101111 | 111 | 6F | o | | | 01110000 | 112 | 70 | p | | | 01110001 | 113 | 71 | q | | | 01110010 | 114 | 72 | r | | | 01110011 | 115 | 73 | s | | | 01110100 | 116 | 74 | t | | | 01110101 | 117 | 75 | u | | | 01110110 | 118 | 76 | v | | | 01110111 | 119 | 77 | w | | | 01111000 | 120 | 78 | x | | | 01111001 | 121 | 79 | y | | | 01111010 | 122 | 7A | z | | | 01111011 | 123 | 7B | { | | | 01111100 | 124 | 7C | \| | | | 01111101 | 125 | 7D | } | | | 01111110 | 126 | 7E | ~ | | | 01111111 | 127 | 7F | DEL (Delete) | 删除 | # **转义序列表** | 转义字符 | 意义 | ASCII码值(十进制) | | -------- | ---------------------------------------- | ------------------- | | \a | 响铃(BEL) | 007 | | \b | 退格(BS) ,将当前位置移到前一列 | 008 | | \f | 换页(FF),将当前位置移到下页开头 | 012 | | \n | 换行(LF) ,将当前位置移到下一行开头 | 010 | | \r | 回车(CR) ,将当前位置移到本行开头 | 013 | | \t | 水平制表(HT) | 009 | | \v | 垂直制表(VT) | 011 | | \' | 单引号 | 039 | | \" | 双引号 | 034 | | \\ | 反斜杠 | 092 | | \ddd | 八进制形式的转义字符;最多后跟三个数字 | 127 | | \xdd | 十六进制形式的转义字符;最多后跟两个数字 | 127 | 最后修改:2022 年 07 月 23 日 © 允许规范转载 打赏 赞赏作者 赞 如果觉得我的文章对你有用,请随意赞赏