内存管理/Gcc编译工具
- 内存四区
代码区: 存放函数体的二进制代码,由操作系统进行管理(cpu执行的机器指令,共享只读)
全局区(全局静态区): 存放全局变量和静态变量以及常量(包含const)
栈区: 由编译器自动分配释放,存放函教的参数值,局部变量等
堆区: 由程序员分配和释放,若程序员不释放程序结束时由操作系统回收
注意:还有一个内核区没有写,用来系统代码,暂时不考虑
- 内存分配
2.1申请
#include <stdlib.h>
void *malloc(size_t size);
参数:所需申请空间的大小
返回值:成功 申请空间的首地址
失败 NULL
2.2释放
void free(void *ptr);
参数:malloc的地址
返回值:无
2.3内存出错
(1)内存泄漏(memory leak):是指申请的内存空间使用完毕之后未回收。
(2)内存溢出(out of memory):是指程序在申请内存时,没有足够的内存空间供其使用。
- Gcc编译工具
使用流程:
- gcc -E gcc.c -o gcc.i
-E:预处理 -o:处理后命名为gcc.i
预处理作用:<1>头文件展开<2>宏定义替换
(2)gcc -S gcc.i -o gcc.s
-S:编译处理 -o:处理后命名为gcc.s
编译处理作用:<1>检查语法错误<2>生成汇编文件
(3)gcc -c gcc.s -o gcc.o
-C:汇编处理
汇编处理作用:<1>生成二进制文件/目标文件
(4)gcc gcc.o -o test
链接处理作用:<1>生成可执行文件
出现问题:
在上述(1)(2)(3)步骤后,不需要第(4)步,直接就可以运行.
解决:-E -S 大写,-c小写,当-C为大写时-C 选项,阻止 GCC 删除源文件和头文件中的注释
所以-c改为小写
辅助记忆:
ESC:编译流程前三个步骤的标记字符
ISO:编译流程进行前三个步骤的文件后缀
最后一步链接不需要标记字符,生成可执行文件.exe(但是不显示.exe)
实现时的简化写法
- 分两步写
<1>gcc -c gcc.c -o gcc.o
<2>gcc gcc.o -o test
- 一步写
<1>gcc gcc.c -o test
3.1Gcc补充
- -c,只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件。
- -o output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。
<1>o:小写,对应下面大写
- -g,产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项。
- -O,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。
Gcc -O test.c -o test -lphread
<1>O大写:
<2>-lpthread:加入线程库头文件
- -O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。
- -I(大i) dirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。
例子1:文件在同一个文件目录下
<1>vi main.c
#include “file.h”
Int main(){
fun();
return 0;
}
<2>vi fum.c
#include<stdio.h>
#include”file.h”
void fun(){
printf(“Hello world!”);
}
<3>vi file.h
void fun();
<4>运行
gcc file.c main.c
例子2:文件不在同一目录下
<1>mkdir include
<2>mv file.h include/
<3>gcc main.c file.c -I include(-大i)
注意: <1>-大i
<2>I指定头文件目录
(1).h 写宏定义#define,结构体,申明函数
(2).c 写函数实现
(3)main.c 使用
(7)-L dirname,将dirname所指出的目录加入到程序函数档案库文件的目录列表中,是在链接过程中使用的参数。
例子:
<1>gcc test.c -o test-lpthread
<2>gcc test.c -o test -L/home/linux/ -lpthread
相同:上述两个都是指定库文件
区别:没有-L的是指定系统自带的库文件
有-L的是指定库文件路径,在使用自己写的库文件时使用
4.条件编译
4.1编译条件的概念
一般情况下,C语言源程序中的每一行代码都要参加编译。但有时候出于对程序代码优化的考虑,希望只对其中一部分内容进行编译,此时就需要在程序中加上条件,让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就是条件编译(conditional compile)
应用场景:代码如果包括x86架构和ARM架构,要进行切换,可用条件编译
4.2代码中的条件编译
方法一:根据宏是否定义过来进行条件编译
#define _DEBUG_
Int main(){
#ifdef _DEBUG_ //#ifnedf是没有定义
printf(“Hello”);
#else
printf(“World”);
}
#endif
运行结果:Hello
方法二:根据宏的值是否为真来进行条件编译
#define VALUE 1
#if VALUE
Printf(Hello“”);
#endif
运行结果:Hello
4.3gcc编译时条件编译
命令行中定义或赋值宏来选择编译
gcc main.c -D _DEBUG_
gcc main.c -D VALUE=1
gcc main.c -D VALUE=1 -D _DEBUG_ 两者结合
注意:#ifndef:根据宏是否定义
#if:根据值是否为真