C语言复习0.1
C程序编译步骤
预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法
gcc -E hello.c -o hello.i
编译:检查语法,将预处理后文件编译生成汇编文件
gcc -S hello.i -o hello.s
汇编:将汇编文件生成目标文件(二进制文件)
gcc -c hello.s -o hello.o
链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去
gcc hello.o -o hello_elf
原码反码补码
源码
- 最高位作为符号位,0表示正,1表示负
- 其他数值部分就是数值本身绝对值的二进制数
- 负数的源码实在其绝对值的基础上,最高位变为1
反码
- 对于正数,原码反码补码相同
- 对于负数,符号位不变,其他部分取反
补码
- 对于正数,原码反码补码相同
- 对于负数,其补码为它的反码加一
- 补码符号位不动,其他位取反,最后整个书加一,得到原码
在计算机系统中,数值一律用补码来存储 主要原因是:
- 统一了零的编码
- 将符号位和其他位统一处理
- 将减法运算转变为加法运算
- 两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃
数据类型
类型限定符
限定符 | 含义 |
---|---|
extern | 声明一个变脸,extren声明的变量没有建立存储空间 |
volatile | 防止编译器优化代码 |
register | 定义寄存器变量,提高效率。register是建议型的指令,而不是命令型指令,如果CPU有空闲寄存器,那么register就生效,如果没有则无效 |
printf格式化输出
打印格式 | 对应数据类型 | 含义 |
---|---|---|
%d | int | 接受整数值并将它表示为有符号的十进制整数 |
%hd | short int | 短整数 |
%hu | unsigned short | 无符号短整数 |
%o | unsigned int | 无符号8进制整数 |
%u | unsigned int | 无符号10进制整数 |
%x,%X | unsigned int | 无符号16进制整数,x对应的是小写,X大写 |
%f | float | 单精度浮点数 |
%lf | double | 双精度浮点数 |
%e,%E | double | 科学计数法表示的数,此处”e”的大小写代表在输出时用的”e”的大小写 |
%p | void* | 以16进制形式输出指针 |
printf附加格式
字符 | 含义 |
---|---|
l | 附加在d,u,x,o前面,表示长整数 |
- | 左对齐 |
m(代表一个整数)0 | 数据最小宽度,将输出的前面补上0直到占满指定列宽为止不可以搭配使用 |
m,n | m指域宽,即对应的输出项在输出设备上所占的字符数。n指精度,用于说明输出的实型数的小数位数。对数值型的来说,未指定n时,隐含的精度为n=6位 |
内存管理
局部变量
局部变量也叫auto自动变量,一般情况下代码块{}内部定义的变量都是自动变量,它有如下特点:
- 在一个函数内定义,只有在函数范围内有效
- 在复合语句中定义,只有在复合语句中有效
- 随着函数调用的技术或复合语句的结束局部变量的声明生命周期也结束
- 如果没有赋初值。内容为随机
静态局部变量
- static局部变量的作用于也是在定义的函数内有效
- static局部变量的生命周期和程序运行周期一样,同时static局部变量的值只能初始化一次,但可以赋值多次
- static局部变量若未赋予初值,则由系统自动赋值,数值型变量自动赋初值0,字符型变量赋空字符
全局变量
- 在函数外定义,可被本文件及其它文件中的函数所共用,若其它文件中的函数调用此变量,须用extern声明
- 全局变量的生命周期和程序运行周期一样
- 不同文件的全局变量不可重名
静态全局变量
- 在函数外定义,作用范围被限制在所定义的文件中
- 不同文件静态全局变量可以重名,但作用域不冲突
- static全局变量的生命周期和程序运行周期一样,同时staitc全局变量的值只初始化一次
extern全局变量声明
- extern int a;声明一个变量,这个变量在别的文件中已经定义了,这里只是声明,而不是定义。
全局函数和静态函数
在C语言中函数默认都是全局的,使用关键字static可以将函数声明为静态,函数定义为static就意味着这个函数只能在定义这个函数的文件中使用,在其他文件中不能调用,即使在其他文件中声明这个函数都没用。
对于不同文件中的staitc函数名字可以相同。
注意:
- 允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰
- 同一源文件中,允许全局变量和局部变量同名,在局部变量的作用域内,全局变量不起作用
- 所有的函数默认都是全局的,意味着所有的函数都不能重名,但如果是staitc函数,那么作用域是文件级的,所以不同的文件static函数名是可以相同的
复合类型
共用体(联合体)
- 联合union是一个能在同一个存储空间存储不同类型数据的类型
- 联合体所占的内存长度等于其最长成员的长度,也有叫做共用体
- 同一内存段可以用来存放几种不同类型的成员,但每一瞬时只有一种起作用
- 共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被覆盖
- 共用体变量的地址和它的各成员的地址都是同一地址
#include <stdio.h>
//共用体也叫联合体
union Test
{
unsigned char a;
unsigned int b;
unsigned short c;
};
int main()
{
//定义共用体变量
union Test tmp;
//1、所有成员的首地址是一样的
printf("%p, %p, %p\n", &(tmp.a), &(tmp.b), &(tmp.c));
//2、共用体大小为最大成员类型的大小
printf("%lu\n", sizeof(union Test));
//3、一个成员赋值,会影响另外的成员
//左边是高位,右边是低位
//低位放低地址,高位放高地址
tmp.b = 0x44332211;
printf("%x\n", tmp.a); //11
printf("%x\n", tmp.c); //2211
tmp.a = 0x00;
printf("short: %x\n", tmp.c); //2211
printf("int: %x\n", tmp.b); //44332211
return 0;
}
枚举
枚举:将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。
定义:
enum 枚举名
{
枚举值表
}
- 在枚举值表中应列出所有可用值,也称为枚举元素
- 枚举值是常量,不能在程序中用赋值语句再对它赋值
- 枚举元素本身由系统定义了一个表示序号的数值从0开始顺序定义为0,1,2 …
#include <stdio.h>
enum weekday
{
sun = 2, mon, tue, wed, thu, fri, sat
} ;
enum bool
{
flase, true
};
int main()
{
enum weekday a, b, c;
a = sun;
b = mon;
c = tue;
printf("%d,%d,%d\n", a, b, c); //2,3,4
enum bool flag;
flag = true;
if (flag == 1)
{
printf("flag为真\n"); //lage为真
}
return 0;
}
typedef
typedef为C语言的关键字,作用是为一种数据类型(基本类型或自定义数据类型)定义一个新名字,不能创建新类型。
- 与#define不同,typedef仅限于数据类型,而不是能是表达式或具体的值
- #define发生在预处理,typedef发生在编译阶段