C高级——gcc编译器与结构体

1 gcc编译器

1.1 gcc四个步骤

1. 预处理: 展开头文件(将头文件里面的函数声明、宏定义、结构体等拷贝当前文件)
 gcc -E hello. -o hello.i
2. 编译:检查语法错误,删除多余的文件内容,并生成汇编文件
gcc -S hello.i -o hello.s
3. 汇编:将汇编文件 翻译成 二进制文件(不包括调用的函数模块)
 gcc -c hello.s -o hello.o
4. 链接:将调用的函数的执行模块(别人写好的函数编译成了二进制放到库里面)链接到本文,
成为可执行的二进制程序。
 gcc hello.o -o hello

1.2 gcc的选项

Gcc最基本的用法是∶gcc [options] [filenames]

-c
只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标
文件,通常用于编译不包含主程序的子程序文件。

-o
output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源
文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。
-g,
产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入
这个选项。
-O(大O)
对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处
理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。
-O2
比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。
-I
dirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用
的参数。
-L
dirname,将dirname所指出的目录加入到程序函数档案库文件的目录列表中,是在链接过
程中使用的参数。
-l 
-lpthread 链接线程库 -lm 链接数学函数库
链接库

2.gdb

  1. 编译代码 需要添加 -g 选项

  2. gdb + 程序名 进入gdb 调试模式 : q 退出

  3. gdb 命令:

l 查看文件 10 行
b + 行号 : 设置断点位置
info b : 查看断点信息
del num: 删除对应编号的断点
r 运行程序
单步调试:
n 不进入函数
s 进入函数
p + 变量名 : 查看变量

3.内存管理

C语言中的内存管理是指为程序中的变量和数据分配内存空间,并在不再使用时释放这些内存空间,以便提高程序的效率并避免内存泄漏。

存储模型

存储类说明符
auto
register
static
exterten

说明:
局部变量默认为auto型
register型变量个数受限
局部static变量具有全局寿命和局部可见性
局部static变量具有可继承性

4 动态内存

malloc/free
void *malloc(size_t num)
void free(void *p)

malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节个数

malloc申请到的是一块连续的内存,有时可能会比所申请的空间大,有时会申请不到内存,返回NULL
 
malloc返回值的类型是void * ,所以在调用malloc时要显式的进行转换,将void *转换成所需要的指针类型

如果free的参数是NULL的话,没有任何效果

释放一块内存中的一部分是不被允许的

注意事项

删除一个指针p(free (p);),实际意思是删除了p所指向的目标(变量或对象等),释放了它所占用的堆空间,而不是删除p本身,释放堆空间后,p成了空悬指针

动态内存分配失败,返回一个空指针,表示发生了异常,堆资源分配不足,分配失败

malloc与free是配对使用的,free只能释放堆空间,如果malloc返回的指针值丢失,则所分配的堆空间无法回收,称为内存泄漏,同一空间重复释放也是危险的,因为该空间可能已经另分配,所以必须妥善的保存malloc返回的指针,以保证不发生内存泄漏,也必须保证不会去重复释放堆内存空间
野指针:
不是NULL指针,是指向“垃圾”内存的指针。“野指针”是很危险的。

“野指针”的成因主要有两种:

-指针变量没有被初始化。
-指针p被free之后,没有置为NULL,让人误以为p十个合法的指针
-指针操作超越了变量的作用范围。这种情况让人防不胜防。
  • 示例代码:
int *ptr = NULL;
ptr = (int *)malloc(5 * sizeof(int));
if(ptr == NULL) {
    printf("内存分配失败");
}

5 函数

  1. 什么是函数:实现特定功能的代码模块

  2. 函数作用:

1. 方便阅读和维护

2. 代码可以重用

3. 提高编程效率
  1. 学习方法
1. 使用别人的函数(使用第三方库函数)

2. 看和查询函数(man手册查询,网络查询)
memset函数

函数功能:memset - fill memory with a constant byte
头文件:#include 
函数的原型: void *memset(void *s, int c, size_t n);
参数说明:
void *s: 清空的目标指针所指向地址
int c: 用来填充的数据
size_t n: 大小
返回值:The memset() function returns a pointer to the memory
area s.

自定义函数

定义函数
2. 声明
3. 调用
4. 传参
5. 返回值:
	1. 返回函数的结束状态: 通常 成功返回0 失败返回 	-1
	2. 返回函数计算结果

int add(int x, int y)
{
return x+y;
}
int pint(char *s)
{
pintf("%s\n",s);
return 0;
}

6 结构体

  1. 结构体是用户自定义的一种构造类型不属于基本数据类型(int char long float double 等)

  2. 用关键字: struct 声明

  3. 一般形式

   struct 结构体名{数据类型 成员1; 数据类型 成员2};
   struct 结构体名{
   数据类型 成员1;
   数据类型 成员2;
   数据类型 成员3;
   };
   花括号的内容称为 域 表 或成员列表
   struct 结构体名: 结构体类型 类似 int n 的 int

man 7 ip
存放 ip地址相关的特殊结构体

   struct sockaddr_in {
   				sa_family_t sin_family; /* address family: AF_INET */
   				in_port_t sin_port; /* port in network byte order */
   				struct in_addr sin_addr; /* internet address */
   };
   /* Internet address. */
   struct in_addr {
   uint32_t s_addr; /* address in network byte order
   */
   };

你可能感兴趣的:(C语言学习,嵌入式学习,c语言)