内存分区
堆区、栈区、全局区、文字常量区、代码区
- 1.堆区:
malloc
、calloc
、realloc
、free
操作,可读可写; - 2.栈区:局部变量、函数形参、返回值 、可读可写
- 3.全局区:全部变量、静态局部变量、静态全局变量 、可读可写;
- 4.文字常量区:常量、字符常量、字符串常量 只读
- 5.代码区:代码的二进制指令 只读
宏函数(空间换时间
) #define
销毁宏undef
#define Uli(a,b) a*b
#define Uli2(a,b) (a)*(b)
Uli(5+2,2+2)=(5+2*2+2)=11
Uli2(5+2,2+2)=((5+2)*(2+2))=28
Uli(Uli(5+2,2+2),Uli2(5+2,2+2))=(5+2*2+2*(5+2)*(2+2))=65//注意此处计算是不能统一计算需要展开
注意:宏函数定义带括号跟不带括号的区别,计算方式也是不同的
- 带参的宏 在预处理时展开 有大量的重复代码(占空间)没有函数调用带来的出入栈测开销(时间)用空间换时间
- 宏的参数没有时间类型 不能保证参数的完整性
- 宏没有作用域的限制,不能作为结构体或者类的成员 (重点)
函数(时间换空间
)
- 函数调用 需要出入栈的开销时间,代码只有一份节约空间,时间换空间
- 函数的参数有类型 ,可以保证参数的完整性
- 有作用域的限制 能作为结构体或者类的成员
静态区static
-
在c语言中定义静态变量的时候,会改变当前变量的生命周期,并改变变量的村粗区域,首先
局部变量
存储在栈中,全局变量存储在堆中,当你使用static进行修饰的时候,改变了变量的存储类型使之存储在静态区
中,这时的生命周期跟全局变量
的生命周期一样都是在等程序的销毁才结束,内存才回收,那么这时候的变量就可以当做全局变量来看,看以下代码
这段代码主要就是循环执行5次test方法,第一种定义变量的时候i作为局部变量
在每次函数执行完毕就直接销毁了,所以每次进入test方法都重新赋值一遍。 第二种方式在方法里面定义静态变量让其变量i
保存在静态区
生命周期同程序销毁一起,所以每次i++的值都保存了下来,直到程序结束 -
static
关键字创建的变量如果不复制默认是0,跟int
、char
这些关键字创建的变量不一样,他们创建出来的都是随机指向一个内存地址
-
static
修饰全局变量,那么这个变量只能在本源文件中使用,原本全局变量默认是具有外部链接属性的,在外部文件中使用只需要使用extern
关键字进行引入,然后同时执行两个文件就行,但是使用了static进行修饰的时候,让其变为只具备内部链接属性
在进行比对不难发现外部定义的变量不能使用了,外部函数
同样也是这种效果,我就不展示
gcc的编译过程
预处理
:头文件包含、宏替换、条件编译、删除注释(不做语法检查)
gcc -E 2.c -o 1.i
编译
:将预处理好的编译成汇编文件(做语法检查)
gcc -S 1.i -o 1.s
汇编
:将汇编文件.s生成二进制文件.o
gcc -c 1.s -o 1.o
链接
:将各个独立的二进制文件+库函数+启动代码生成可执行文件
gcc 1.o -o main
执行./main
简单命令gcc 2.c -Wall
、./a.out
头文件引用的注意事项
#include " "
:从当前目录
查找头文件,如果找不到才从系统指定目录
找头文件。(包用户定义的头文件)
include <>
:只从系统指定目录
去找头文件。(包含系统头文件)
防止头文件重复包含的两种方式
方式一:Linux的方式#ifndef防止头文件重复包含 #define 定义内容 #endif 结束包含
//a.h
#ifndef __A_H__ //文件名大写
#define __A_H__
extern int Add(int a, int b);
#endif
方式二:windows的方式 防止头文件重复包含
//在引用头文件的时候添加
#pragma once
#include "a.h"
条件编译
#ifndef xxx
语句1;
#else
语句2;
#endif
----------------------
#ifdef xxx
语句1;
#else
语句2;
#endif
-------------------------------------
#if xxx
语句1;
#else
语句2;
#endif