(十三)C语言之编译过程

目录

1、内存分区

2、变量的分类

2.1 普通局部变量

2.2 普通全局变量

2.3 静态局部变量

2.4 静态全局变量

2.5 总结

3、函数的分类

3.1 全局函数

3.2 静态函数

4、C语言编译过程 

4.1 预编译:头文件包含

4.2 预编译:宏替换

4.2.1 不带参数的宏

4.2.2 带参数的宏(宏函数)

4.2.3 宏函数和普通函数的区别

5、预编译:条件编译

5.1 定义形式:

5.2 防止有文件重复包含


1、内存分区

运行中的内存分区:

分区读写特性变量存放内否取地址变量初始值
堆区可读可写

必须使用库函数malloc、calloc、realloc动态申请,使用完成后free手动释放

不能内容不确定
栈区可读可写局部变量、函数形参、返回值>4B内容不确定
全局区可读可写全局变量、静态局部变量、静态全局变量0
文字常量区只读字符常量、字符串常量、符号常量等不能---
代码区只读代码的二进制指令不能---

综上表,用户定义的变量可以存储在堆区、栈区、全局区和文字常量区。

下面,我们就看看这些变量分别有什么特点。

2、变量的分类

2.1 普通局部变量

定义方式:定义在{ } 中的变量为普通局部变量,且不能被static修饰

作用范围:当前的{ }内有效

生命周期:当前{ }结束,局部变量释放

存储区域:栈区

不初始化问题:不初始化内容不确定

总结:

  1. 普通局部变量不初始化内容不确定。
  2. 复合语句结束,普通局部变量被释放
  3. 局部变量如果同名情况,采用就近原则

2.2 普通全局变量

定义方式:在函数外定义的变量,且不能被static修饰

作用范围:当前源文件和其他源文件都有效(其他源文件使用需要extern声明)

生命周期:整个进程,进程结束,普通全局变量释放

存储区域:全局区

不初始化问题:不初始化内容为0

总结:

  1. 普通全局变量不初始化内容为0
  2. 如果其他源文件想使用普通全局变量,需要用extern声明

2.3 静态局部变量

定义方式:定义在{ } 中定义,且被static修饰

作用范围:当前的{ }内有效

生命周期:整个进程,进程结束,静态局部变量释放

存储区域:全局区

不初始化问题:不初始化内容为0

总结:

  1. 静态局部变量不初始化内容为0
  2. 整个进程有效,进程结束,静态局部变量才被释放

2.4 静态全局变量

定义方式:定义在函数外,且被static修饰

作用范围:只能在当前源文件使用

生命周期:整个进程,进程结束,静态全局变量释放

存储区域:全局区

不初始化问题:不初始化内容为0

总结:

  1. 静态局部变量不初始化内容为0
  2. 只能在当前源文件使用

2.5 总结

普通局部变量,定义在栈区,不初始化内容不确定,当前{ }有效,{ }结束被释放

普通全局变量,存储在全局区,不初始化内容为0,当前源文件和其他源文件有效,进程结束被释放

静态局部变量,存储在全局区,不初始化内容为0,当前{ }有效,进程结束被释放

静态全局变量,存储在全局区,不初始化内容为0,当前源文件有效,进程结束被释放

3、函数的分类

3.1 全局函数

全局函数可以被其他源文件调用,C语言默认都是全局函数。

其他源文件调用时需要外部声明extern修饰

3.2 静态函数

静态函数只能在当前源文件使用,不能在其他源文件使用,即使是外部声明了也不可以

4、C语言编译过程 

C语言编译分为四个过程:

①预处理:头文件包含、宏替换、删除注释、条件编译。不做语法检查。

gcc -E main.c -o main.i

②编译:做语法、词法检查,然后生成汇编文件。

gcc -S main.i -o main.s

③汇编:将汇编文件生成二进制文件。

gcc -c main.s -o main.o

④链接:结合二进制文件、所需要的库、启动代码生成可执行文件

 gcc main.o -o main

在编译时也可以一步到位:

gcc main.c
或者
gcc main.c -o main

4.1 预编译:头文件包含

头文件包含一般会用到#include <>或者#include " "。

问:#include <>或者#include " "的区别?

答:#include < >:直接从系统指定的目录下寻找头文件,一般在包含系统自带的头文件时使用。

        #include " ":先从本地目录下寻找,如果找不到,再从系统指定目录下寻找。一般在包含用户自定义的头文件时使用。

问:什么是头文件 ,头文件里面包含什么?

答:C语言中头文件一般是 .h 文件。

       头文件中包含变量的声明,函数的声明,类型定义,宏定义等。

头文件包含:本质就是将头文件(.h文件)中的内容复制到#include的位置上。

注:编译时不需要将.h文件一起编译,只需要编译.c文件即可

4.2 预编译:宏替换

宏的定义,就是使用#define关键字将一个固定的词替换成另一个词,在预编译个过程中,会自动展开。

注:在定义宏时,最后不加 ; 号

4.2.1 不带参数的宏

格式:#define 宏名称 要替换的名称

4.2.2 带参数的宏(宏函数)

宏函数本质是宏,而不是函数。 

格式:#define 宏名(参数) 表达式

注意,注意,注意:宏函数在替换时就是单纯的替换,不会进行数据操作!

4.2.3 宏函数和普通函数的区别

宏函数:本质是宏,在预编译阶段展开;没有出入栈的开销;参数没有类型,不能保证参数完整性;如果使用次数多占用内存就大,用空间换时间。

函数:有出入栈的开销;参数有类型,可以保证参数的完整性,占用内存固定,用时间换空间。

5、预编译:条件编译

5.1 定义形式:

第一种:如果XXX为真,则编译语句1,否则编译语句2.

#if XXX
    语句1
#else
    语句2
#endif

第二种:如果定义了XXX,则编译语句1,否则编译语句2

#ifdef XXX
    语句1
#else
    语句2
#endif

第三种:如果没有定义XXX,则编译语句1,否则编译语句2

#ifndef XXX
    语句1
#else
    语句2
#endif

注:条件编译实在预编译阶段处理的,预编译阶段直接将不符合条件的语句过滤掉,被过滤的语句在接下来的编译过程中都不会进行处理,相当于被删除掉了。而 if...else...是条件判断语句,不管符不符合条件都会被编译。

5.2 防止有文件重复包含

linux(推荐):

#ifndef __BASE_H__
#define __BASE_H__

base.h头文件的内容

#endif

windows:

#pragma once

base.h头文件的内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值