16.预处理、动态库、静态库

news2025/1/31 11:07:15

C语言编译过程

1.预处理
将.c中的头文件展开、宏展开
生成的文件是.i文件
2.编译
将预处理之后的.i文件生成.s汇编文件
3.汇编
将.s汇编文件生成.o目标文件
4.链接
将.o文件链接成目标文件(可执行程序)

Linux下GCC编译器编译过程

gcc -E hello.c -o hello.i 1.预处理
gcc -S hello.i -o hello.s 2.编译
gcc -c hello.s -o hello.o 3.汇编
gcc hello.o -o hello_elf 4.链接

include预处理

#include<> //用尖括号包含头文件,在系统指定的路径下找头文件

#include" " //用双引号包含头文件,先在当前目录下找头文件,再到系统指定路径下查找。

注意:include经常用来包含头文件,可以包含.c文件,但include包含的文件会在预编译被展开,如果一个.c被包含多次,在预处理时会被展开多次,导致函数重复定义。尽量避免包含.c文件。
预处理只是对include等预处理操作进行处理并不会进行语法检查,这个阶段有语法错误不会报错,第二个阶段即编译阶段才会进行语法检查。

define定义宏

宏是在预编译的时候进行替换。

1.不带参宏

#define PI 3.14

在预编译的时候如果代码中出现了PI就用3.14去替换。
宏的好处:只需要修改宏定义,其他地方在预编译的时候就会重新替换。

注意:宏定义后边不要加分号。

宏定义的作用范围:从定义的地方到本文件末尾。
如果想在中间终止宏的定义范围

#undef PI //终止PI的作用

#include<stdio.h>
#define PI 3.1415926
int main()
{
	double f;
	printf("PI=%lf\n", PI);
#undef PI
#define PI 3.14
	f = PI;
	printf("f=%lf\n", f);
	return 0;
}

在这里插入图片描述

2.带参宏

#define S(a,b) a*b

注意带参宏的形参a和b没有类型名
S( 2, 4 )将来在预处理的时候替换成 实参替代字符串的形参,其他字符保留

#include<stdio.h>
#define S(a,b) a*b
int main()
{
	int num;
	num = S(2, 4);
	printf("num=%d\n", num);
	num = S(3, 5);
	printf("num=%d\n", num);
	num = S(4, 6);
	printf("num=%d\n", num);
	num = S(3+5, 7);//3+5*7
	printf("num=%d\n", num);
	return 0;
}

在这里插入图片描述
解决方法:

#include<stdio.h>
#define S(a,b) (a)*(b)
int main()
{
	int num;
	num = S(2, 4);
	printf("num=%d\n", num);
	num = S(3+5, 7);//(3+5)*(7)
	printf("num=%d\n", num);
	return 0;
}

在这里插入图片描述

3.带参宏和带参函数的区别

带参宏被调用多少次就会展开多少次,执行代码的时候没有函数调用的过程,不需要圧栈弹栈。所以带参宏浪费空间,因为被展开多次,节省时间。
带参函数,代码只有一份,存在代码段,调用的时候去代码段取指令,调用的时候要圧栈弹栈。有调用的过程。所以说,带参函数是浪费了时间,节省了空间。
带参函数的形参是有类型的,带参宏的形参没有类型名。

选择性编译

1.#ifdef

#ifdef AAA
代码段1
#else
代码段2
#endif

如果在当前.c ifdef上定义过AAA,就编译代码段一,否则编译代码段二
注意和if else 语句的区别,if else 语句都会被编译,通过条件选择执行代码,而选择性编译,只有一块代码被编译。

#include<stdio.h>
#define AAA
int main()
{
#ifdef AAA
	printf("hello world!\n");
#else
	printf("hello china!\n");
#endif
	return 0;
}

在这里插入图片描述

2.#ifndef

#ifndef AAA
代码段1
#else
代码段2
#endif

和 #ifdef 互补。
这种方法,经常用在防止头文件重复包含。

#include"5.h"
#include"5.h"
int main()
{
	return 0;
}

5.h:

#ifndef __5_H__ //防止头文件重复包含
#define __5_H__
extern int fun(int x, int y);
#endif

3.#if

#if 表达式
程序段一
#else
程序段二
#endif

如果表达式为真,编译第一段代码,否则编译第二段代码。

#include<stdio.h>
int main()
{
#if 1
	printf("hello world\n");
#else
	printf("hello china!\n");
#endif
	return 0;
}

在这里插入图片描述
选择性编译都是在预编译阶段干得事情。

静态库

1.动态编译

动态编译使用的是动态库文件进行编译

gcc hello.c -o hello

默认使用动态编译方法。

2.静态编译

静态编译使用静态库文件进行编译

gcc -static hello.c -o hello

3.静态编译和动态编译的区别

  • 使用的库文件格式不一样,动态编译使用动态库,静态编译使用静态库。

  • 静态编译要把静态库文件打包编译到可执行程序中。

  • 动态编译不会把动态库文件打包编译到可执行程序中,它只是编译链接关系。

4.静态库文件的制作

gcc -c mylib.c -o mylib.o
ar rc libtestlib.a mylib.o

注意:静态库起名必须以lib开头,以.a结尾。

编译程序:
方法a

gcc -static mytest.c libtestlib.a -o mytest

方法b
可以指定头文件及库文件的路径:
比如将libtestlib.a mylib.h 移动到/home/edu下

mv libtestlib.a mylib.h /home/edu

编译程序命令:

gcc -static mytest.c -o mytest -L/home/edu -ltestlib -I/home/edu

注意:
-L 是指定库文件的路径
-l(小L) 指找哪个库,只需要库文件名lib后面,.a前面的部分
-I(大i) 指头文件的路径

方法c
将库文件及头文件放到系统默认路径下
库文件的默认路径 /lib 或者是 /usr/lib
头文件的默认路径是 /usr/include

sudo mv libtestlib.a /usr/lib
sudo mv mylib.h /usr/include

编译程序命令

gcc -static mytest.c -o mytest -Itestlib

5.动态库的制作

制作动态链接库

gcc -shared mylib.c -o libtestlib.so
//使用gcc编译、制作动态链接库

动态链接库的使用:
方法a
库文件、头文件均在当前目录下

gcc mytest.c libtestlib.so -o mytest
export LD_LIBRARYA_PATH=./:$LD_LIBRARY_PATH
./mytest

方法b
库文件、头文件假设在/opt目录

gcc mytest.c -o mytest -L/home/teacher -ltestlib -I/home/teacher

编译通过,运行时出错,编译时找到了库函数,但链接时找不到库,执行以下操作,把当前目录加入搜索路径

export LD_LIBRARYA_PATH=./home/edu:$LD_LIBRARY_PATH
./mytest //可找到动态链接库

方法c
库函数、头文件均在系统路径下

cp libtestlib.so /usr/lib
cp mylib.h /usr/include
gcc mytest.c -o mytest -ltestlib

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/39767.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++11标准模板(STL)- 算法(std::upper_bound)

定义于头文件 <algorithm> 算法库提供大量用途的函数&#xff08;例如查找、排序、计数、操作&#xff09;&#xff0c;它们在元素范围上操作。注意范围定义为 [first, last) &#xff0c;其中 last 指代要查询或修改的最后元素的后一个元素。 返回指向第一个大于给定值…

[附源码]Python计算机毕业设计钓鱼爱好者交流平台

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Java项目:电器商城系统(java+SSM+JSP+jQuery+javascript+Mysql)

源码获取&#xff1a;俺的博客首页 "资源" 里下载&#xff01; 项目介绍 本项目分为前后台&#xff0c;前台为普通用户登录&#xff0c;后台管理员登录&#xff1b; 管理员角色包含以下功能&#xff1a; 修改个人信息,员工信息管理,商品管理,图片管理,图表管理,用户…

解决vscode远程安装插件不了、安装太慢问题

一、问题描述 一直显示正在安装&#xff0c;几个小时也没动静&#xff0c;特别是那个c/c插件的安装。 二、解决方法 1、采用手动安装插件的方式 步骤&#xff1a; ①、先去这个网站找你要安装的插件&#xff0c;然后下载到本地电脑。 All categories Extensions - Visual Studi…

分汤000

题目链接 分汤 题目描述 注意 没有提供 0ml 的 汤A 和 100ml 的 汤B 这种操作如果汤的剩余量不足以完成某次操作&#xff0c;我们将尽可能分配 解答思路 由题意得&#xff0c;首先想到的是动态规划&#xff0c;关键是规律以及终止条件是怎样的由于分汤都是在25的倍数上进行…

内点法最优潮流matlab程序

内点法最优潮流matlab程序 一、概述最优潮流问题 1.最优潮流和基本潮流的比较潮流计算可以归结为针对一定的扰动变量p(负荷情况)&#xff0c;根据给定的控制变量u(如发电机的有功出力、无功出力或节点电压模值等)&#xff0c;求出相应的状态变量x(如节点电压模值及角度)&#x…

如何控制MySQL事务提交后,刷redo-log的策略?

既然涉及到事务提交&#xff0c;那么我们就是以InnoDB来说明的。 MySQL有一个参数&#xff0c;能够控制事务提交时&#xff0c;刷redo log的策略。该参数为&#xff1a;innodb_flush_log_at_trx_commit。 策略1,set global innodb_flush_log_at_trx_commit 0 该方式可以获得…

天然气潮流计算matlab程序

天然气潮流计算matlab程序 1 天然气潮流计算理论 由于天然气涉及到流体的运动方程&#xff0c;直接计算非常复杂&#xff0c;因此需要提前做出一些假设来简化计算&#xff0c;经过研究&#xff0c;适当的假设对结果影响很小&#xff0c;因此本文对天然气系统做出如下假设&#…

安装包UI美化之路-进度条的多种配置方法

安装包的进度条&#xff0c;你真正关心过么&#xff1f; 你知道如何配置出美观的进度条么&#xff1f;遇到特殊的进度条需求&#xff0c;你知道怎么实现么&#xff1f; 安装包的美化过程中&#xff0c;有一个细节比较重要&#xff0c;那就是进度条的呈现样式&#xff01; 呈现…

3、网关和BFF

一、网关和BFF的演进 v1 使用nginx负载均衡简单的微服务体系&#xff1b; v2 nginx直接暴露 v2.5无线BFF v3 集群BFF无线网关 v4无线网关、无线BFF根据业务集群化&#xff0c;废弃nginx集群 二、网关和反向代理 网关和反向代理的选择&#xff1a; 关于网关集群问题&#…

【自动化持续集成必备基础】pipeline常用功能

简介 ​pipeline是一套运行在jenkins上的工作流框架&#xff0c;可以实现复杂流程的编排和可视化运行 pipeline支持两种语法&#xff1a;Declarative Pipeline(声明式流水线)和Scripted Pipeline (脚本式流水线) 本文重点介绍主流的声明式流水线 创建流水线项目 在Jenkins中如果…

SpringBoot SpringBoot 原理篇 2 自定义starter 2.4 使用属性配置设置功能参数【1】

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 原理篇 文章目录SpringBootSpringBoot 原理篇2 自定义starter2.4 使用属性配置设置功能参数【1】2.4.1 直接开干2.4.2 小结…

linux驱动之调试技巧--- 应用程序远程gdb+vscode调试应用程序, 串口kgdboc调试.ko驱动程序

环境: Ubuntu: Ubuntu 22.04.1 开发板: imx6ull linux内核版本: Linux4.9.88 虚拟机: vmware15 交叉编译工具gcc版本: 4.9.4 (Linaro GCC 4.9-2017.01) arm-linux-gdb版本: gdb (Linaro_GDB-2017.01) 7.10.1.20160210 先决条件 开发板 虚拟机 PC 可互通网络 交叉编译环境已经搭…

哈希(Hash)

文章目录一、哈希是什么&#xff1f;二、哈希冲突三、开放定址法1.线性探测2.二次探测四、拉链法/哈希桶五、哈希的应用1.位图1.1 面试题1.2 位图概念1.3 位图的应用2.布隆过滤器2.1概念2.2布隆过滤器的查找2.3布隆过滤器的删除一、哈希是什么&#xff1f; Hash&#xff0c;一般…

语音识别系列︱利用达摩院ModelScope进行语音识别+标点修复(四)

终于有时间更新语音识别系列了&#xff0c;之前的几篇&#xff1a; 语音识别系列︱用python进行音频解析&#xff08;一&#xff09; 语音识别系列︱paddlehub的开源语音识别模型测试&#xff08;二&#xff09; 语音识别系列︱paddlespeech的开源语音识别模型测试&#xff08;…

1. JVM类加载机制

1. JVM类加载机制图解 下面我们来详细分析一下这个图解 1.1 其中loadClass()方法的调用的类加载的过程有如下几步 加载->验证->准备->解析->初始化->使用->卸载 加载&#xff1a;在硬盘上查找并通过IO读入字节码文件&#xff0c;当使用到这类的时候才会加…

[GYCTF2020]Ezsqli

先试一下万能密码 1 or 11# 发现有过滤&#xff0c;fuzz看一下过滤了什么 if&#xff0c;|&#xff0c;|| 没过滤&#xff0c;过滤了information_schema MySQL5.7新特性&#xff1a; 由于performance_schema过于复杂&#xff0c;所以mysql在5.7版本中新增了sys schemma&#x…

Docker实战之Redis主从集群搭建实战

实战 本实验将练习三主三从的Redis的docker集群快速搭建&#xff0c;实现集群的动态扩容和缩容&#xff0c;主从切换等常见实践项目。 拉取镜像 docker pull redis:6.0.8搭建主从 docker run -d --name redis-node-1 --net host --privilegedtrue -v /data/redis/share/red…

Allegro输出DXF文件操作指导

Allegro输出DXF文件操作指导 Allegro支持输出DXF文件,用于检查PCB的结构,具体操作如下 首先在PCB上打开需要的输出的层面,需要哪层开哪层,如下图所示 点击file-export 弹出一个对话框,输入文件名,格式选择Reversion14 ,单位选择mm,精度选择4 然后点击Edit 会出现一…

视频播放

QMediaPlayer不仅可以播放音频&#xff0c;还可以播放视频&#xff0c;不过要在屏幕上显示的话需要使用QVideoWidget和QGraphicsVideoItrm或自定义的类。QMovie 播放GIF文件QVideoWidget和QGraphicsVideoItrm都属于QMulimedia Widgets模块QVideoWidget 继承自QWiaget&#xff0…