C语言-预处理与库
预处理、动态库、静态库
1. 声明与定义分离
一个源文件对应一个头文件
注意:
- 头文件名以
.h作为后缀头文件名要与对应的原文件名一致
例:
源文件:01_code.c
#include <stdio.h>
int num01 = 10;
int num02 = 20;
void add(int a, int b)
{int sum = a + b;printf("%d + %d = %d\n", a, b, sum);
}void mul(int a, int b)
{int mul = a + b;printf("%d + %d = %d\n", a, b, mul);
}
头文件:01_code.h
extern int num01;
extern int num02;
extern void add(int, int);
extern void mul(int, int);
测试文件:test.c
#include <stdio.h>
#include "01_code.h"int main(int argc, char const *argv[])
{printf("num01 = %d\n", num01);printf("num02 = %d\n", num02);add(10, 20);mul(10, 20);return 0;
}
编译:
命令:
gcc test.c 01_code.c./a.out输出:
num01 = 10 num02 = 20 10 + 20 = 30 10 + 20 = 30
2. 预处理
2.1 c语言编译过程
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、链接
1、预编译
- 将
.c中的头文件展开、宏展开生成的文件是.i文件2、编译
- 将预处理之后的
.i文件生成.s汇编文件3、汇编
- 将
.s汇编文件 生成.o文件4、链接
- 将
.o文件 链接成目标文件(即可执行文件)
预编译包含
展开头文件
定义头文件
选择性编译注意:预编译的内容以 # 开头
2.2 include
作用:展开头文件
语法:
#include <>
用
尖括号包含的头文件, 在 系统指定的路径下 找头文件#:表示预编译
#include ""
用
双引号包含头文件,先在当前目录下找 头文件,找不到,再到系统指定的路径下找
注意:
1、include 经常用来包含头文件,可以包含
.c文件,但是大家不要包含.c因为 include 包含的文件会在预编译被展开,如果一个.c 被包含多次,展开多次,会导致函数重复定义。所以不要包含.c 文件2、预处理只是对 include 等预处理操作进行处理,并
不会进行语法检查,这个阶段有语法错误也不会报错,第二个阶段即编译阶段才进行语法检查。
例:
#include "01_code.h"//等价于 下面, 即在源文件中展开下面代码extern int num01;
extern int num02;
extern void add(int, int);
extern void mul(int, int);
2.2 宏:define
作用:在预处理 处理定义 类似于 变量或函数的东西。即:宏是在预编译的时候进行替换 。
2.2.1 不带参宏
语法:
#define 宏名 值 //宏定义#undef 宏名 //取消宏定义
注意:
1、如果定义该类型的宏(不带参的宏),
值可以省略2、无需分号结束
3、在 宏定义后,取消定义前 可以使用
4、只能在
当前文件中使用
例:
#include <stdio.h>
#define PI 3.14
int main(int argc, char const *argv[])
{printf("pi = %f\n", PI);
#undef PI //取消宏定义return 0;
}
2.2.2 带参宏
语法:
#define 宏名(形参) 体
注意:
1、形参没有数据类型
2、
带参宏与带参函数的区别
宏:在
预编译时对其进行 替换,如果一个文件中多次使用宏,那意味着要替换多次,此时就需占用内存,所以占据的内存多
- 产生的预编译时期
- 占内存多
- 速度快
函数:在程序运行时在代码区存储一份,每次调用该函数都需在代码区寻找,将其放入栈内存中(压栈),当函数执行完毕后,从栈中移除(弹栈)
- 产生在运行时
- 占内存少
例:
#include <stdio.h>
#define ADD(a, b) a+b
#define MUL(a, b) a*b
#define MUL02(a, b) (a)*(b)
int main(int argc, char const *argv[])
{int sum = ADD(20, 30);printf("sum=%d\n", sum);int mul = MUL(20, 30);printf("mul=%d\n", mul);int mul02 = MUL(20+10, 30+10); //20 + 10 * 30 +10printf("mul=%d\n", mul02);int mul03 = MUL02(20+10, 30+10); //(20 + 10) * (30 + 10)printf("mul=%d\n", mul03);return 0;
}

2.2.3 小结
宏就是在
预编译时期对其进行替换不带参宏替换的是一个值
带参宏替换的是一段代码
2.3 选择性编译
作用:选择代码是否被编译
语法:

例1:判断存在
优点:节省内存,只加载需要的部分
#include <stdio.h>int main(int argc, char const *argv[])
{#ifdef XXXprintf("有定义宏名为XXX的宏\n");#elseprintf("没定义宏XXX\n");#endifreturn 0;
}


编译时定义宏:

例2:判断不存在,和头文件配合使用,防止多次引用头文件
#include <stdio.h>
#include "04_test.h"
#include "04_test.h"
int main(int argc, char const *argv[])
{#ifndef YYYprintf("1111\n");#elseprintf("2222\n");#endifreturn 0;
}
头文件:04_test.h
#ifndef TEST
#define TEST
extern int num;
//...
#endif
#ifndef 使用含义:
1、
第一次引用头文件,没有定义TEST宏,然后定义,再写头文件内容;2、假如
再次引用头文件时,第一次已经定义过TEST宏了,所以直接结束,啥也不干。
源码写法:

例3:判断是否成立
#include <stdio.h>
int main(int argc, char const *argv[])
{#if ScORE > 85printf("A\n");#elif ScORE > 70printf("B\n");#elif ScORE >= 60printf("c\n");#elseprintf("D\n");#endifreturn 0;
}

3. 库
概念:库也叫代码库,可以把一个些目标文件合并在一起方便使用。
3.1 分类
静态库
动态库
静态库、动态库的区别:

注意:
- 程序中引入的文件在动态库与静态库同时存在两份
- 静态编译程序引入静态库中的该文件
- 动态编译程序引入动态库中的该文件
3.2 编译命令
动态编译:
gcc 源文件名 -o 生成的可执行文件名
静态编译:
gcc -static 源文件名 -o 生成的可执行文件名
3.3 静态库
3.3.1 制作
gcc -c 源文件名.c -o 生成的二进制文件名.o
ar rc lib静态库名称.a 生成的二进制文件名.o
注意:
静态库起名的时候必须 以lib 开头以.a结尾
步骤:
-
新建文件夹:
06_code -
源文件:
myfun.c#include <stdio.h>void add(int a, int b) {printf("my_sum = %d\n", (a+b)); }void mul(int a, int b) {printf("my_mul = %d\n", (a*b)); } -
头文件:
myfun.hextern void add(int a, int b); extern void mul(int a, int b); -
制作

3.3.2 使用
情况1:使用静态库的文件与静态库 在同一文件夹下
命令:
gcc 源文件名 静态库名称 -o 生成的可执行文件名
测试文件:test01.c
#include <stdio.h>
#include "myfun.h" //可以不写,但是会报警告
int main(int argc, char const *argv[])
{add(10, 3);return 0;
}
编译:

情况2:使用静态库的文件与静态库 不在同一文件夹下
注意:
为了让静态库文件与其对应的头文件和使用静态库文件不在同一文件夹下,所以
创建includes与libs文件夹
includes文件用于存储头文件
libs文件夹存储静态库文件
mkdir includes mkdir libs mv myfun.h includes/ mv libmyfun.a libs/参数
-L 引用的静态库所在的路径 -l 静态库名, 去掉lib与.a -I 头文件所在路径命令
gcc 源文件名 -L 静态库所在的路径 -l 静态库名 -I 头文件所在路径 -o 生成的可执行文件名
情况3:静态库文件与对应的头文件 在系统文件夹下
系统库路径:
/usr/include 存储头文件 /usr/lib 或 /lib 存储库文件注意:
# 为了让静态库文件与其对应的头文件和系统文件夹下,所以需要移动 sudo mv includes/myfun.h /usr/include sudo mv libs/libmyfun.a /usr/lib命令:
gcc 源文件名 -l 静态库名 -o 生成的可执行文件名
3.4 动态库
3.4.1 制作
命令:
gcc -shared 源文件名 -o 生成的动态库文件名.so
3.4.2 使用
情况1:使用动态库的文件与动态库在同一文件夹下
命令:
gcc 源文件名 动态库名称 -o 生成的可执行文件名
情况2:使用动态库的文件与动态库不在同一文件夹下
命令:
gcc 源文件名 -L 动态库所在路径 -l 动态库名称 -I 头文件所在路径注意:
- 动态库名需要去掉前面的
lib与后面.so
情况3:静态库文件与对应的头文件在系统文件夹下
命令:
gcc 源文件名 -l 静态库名 -o 生成的可执行文件名
相关文章:
C语言-预处理与库
预处理、动态库、静态库 1. 声明与定义分离 一个源文件对应一个头文件 注意: 头文件名以 .h 作为后缀头文件名要与对应的原文件名 一致 例: 源文件:01_code.c #include <stdio.h> int num01 10; int num02 20; void add(int a, in…...
王道数据结构课后代码题p40 9.给定一个带表头结点的单链表,写出算法 : 按递增次序输出单链表中各结点的数据元素并释放结点 (c语言代码实现)
本题代码如下(有注释) void delete_min(linklist* head) {while ((*head)->next ! NULL)//循环到只剩下头节点{lnode* pre *head;//pre为元素最小结点的前驱结点指针lnode* p (*head)->next;//p为工作指针lnode* q;//指向被删除的结点while (p-…...
对系统的 Go 版本进行升级
方法一 直接升级系统的 Go 版本 注意以下操作仅适用于:amd64 架构的 Centos 系统。如果需要适配其他架构,需要自行编写代码实现。 手动执行: # 显示当前版本 go version # 查看环境变量 cat /etc/profile # 进入 go 的安装目录,…...
【从删库到跑路 | MySQL总结篇】事务详细介绍
个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【MySQL学习专栏】🎈 本专栏旨在分享学习MySQL的一点学习心得,欢迎大家在评论区讨论💌 目录 一、事务…...
七牛云1024创建节-赛后有感
距离比赛结束已经过去快半个月时间,七牛云又发起了有奖征文的活动,正好借此机会记录一下自己参加这次比赛的经历,感受和一些比赛的心得。 如何了解到的比赛信息 其实我很早就开始关注七牛云了,最早是在今年二三月的时候…...
CSS 选择器优先级,!important 也会被覆盖?
目录 1,重要性2,专用性3,源代码顺序 CSS 属性值的计算过程中。其中第2步层叠冲突只是简单说明了下,这篇文章来详细介绍。 层叠冲突更广泛的被称为 CSS选择器优先级计算。 为什么叫层叠冲突,可以理解为 CSS 是 Cascadi…...
关于src别名的配置之tsconfig.json配置
tsconfig.json {"compilerOptions": {"baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录"paths": { //路径映射,相对于baseUrl"/*": ["src/*"] }} } ① "baseUrl": &…...
Mybatis如何执行批量操作
文章目录 Mybatis如何执行批量操作使用foreach标签 使用ExecutorType.BATCH如何获取生成的主键 Mybatis如何执行批量操作 使用foreach标签 foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach标签的属性主要有item,index&…...
LeetCode 1094. 拼车:优先队列
【LetMeFly】1094.拼车:优先队列 力扣题目链接:https://leetcode.cn/problems/car-pooling/ 车上最初有 capacity 个空座位。车 只能 向一个方向行驶(也就是说,不允许掉头或改变方向) 给定整数 capacity 和一个数组…...
项目开发维护技术文档(总结梳理)
目录 一、项目背景 二、架构设计 1.技术栈 2.架构图 3.代码结构 三、模块划分 1.用户模块 2.商品模块 四、开发规范 1.命名规范 2.代码格式 3.版本控制 五、部署流程 1.环境要求 2.部署流程 六、问题解决 1.数据库连接异常 2.Redis缓存失效 七、参考资料 项…...
01_学习使用javax_ws_rs_上传文件
文章目录 1 前言2 Maven 依赖3 上传接口4 如何解析 MultipartFormDataInput5 结语 1 前言 使用 Spring MVC 来处理文件上传,想必是大家耳熟能详的了,如下代码: ResponseBody PostMapping("/upload") public String upload(Request…...
MFC 发布CLXHHandleEngine动态库1.0.0.0版本
第一版发布以下功能,此项目使用VS2013创建,项目配置包括Unicode的Mdd,md与多字节版本: //MFC Grid表格 #include "../MFCGridCtrl/GridCtrl.h" //使用AES与Base64加密解密可以与java中的AES加解密衔接 //AES加密解密 #include &q…...
MicroPython 基于microdot框架搭建网页服务器
MicroPython 基于microdot框架搭建网页服务器 简介简单demo 简介 Microdot是一个极简的Python web框架,灵感来自于Flask,它被设计用来运行在资源有限的系统上,如微控制器。它运行在标准的Python和MicroPython上。 API参考microdot 资源下载m…...
FL Studio21.2汉化永久中文语言包
FL Studio21.2这款软件在国内被广泛使用,因此又被称为"水果"。它提供音符编辑器,可以针对作曲者的要求编辑出不同音律的节奏,例如鼓、镲、锣、钢琴、笛、大提琴、筝、扬琴等等任何乐器的节奏律动。此外,它还提供了方便快…...
Glide结合OkHttp保证短信验证接口携带图形验证码接口返回Cookie值去做网络请求
一、实现效果 二、步骤 注意:仅展示核心部分代码 1、导入依赖 api com.github.bumptech.glide:glide:4.10.0 kapt com.github.bumptech.glide:compiler:4.10.0 api com.squareup.okhttp3:okhttp:3.11.0 api com.squareup.okhttp3:logging-interceptor:3.11.02、自…...
怎样用Ajax提交from表单并接收其中的json数据
怎样用Ajax提交表单并接收其中的json数据 需求:实现点击按钮后,数据以表单形式提交至服务器,并接收来自服务器的返回数据。过程中页面不刷新。 AJAX 不是新的编程语言,而是一种使用现有标准的新方法。AJAX 是与服务器交换数据并…...
【动态规划】LeetCode-746LCR 088.使用最小花费爬楼梯
🎈算法那些事专栏说明:这是一个记录刷题日常的专栏,每个文章标题前都会写明这道题使用的算法。专栏每日计划至少更新1道题目,在这立下Flag🚩 🏠个人主页:Jammingpro 📕专栏链接&…...
Unity 接入TapADN播放广告时闪退 LZ4JavaSafeCompressor
通过跟踪安卓日志,发现报如下错误 Didnt find class "com.tapadn.lz4.LZ4JavaSafeCompressor" 解决方案: 去掉Minify这边的勾选,再打包即可。...
【九】linux下部署frp客户端服务端实践(内网穿透)
linux下部署frp客户端服务端实践 简介: 今天有一个这样的需求,部署在公司内部局域网虚拟机上的服务需要在外网能够访问到,这不就是内网穿透的需求吗,之前通过路由器实现过,现在公司这块路由器不具备这个功能了&#x…...
华为1+x网络系统建设与运维(中级)-练习题2
一.设备命令 LSW1 [Huawei]sys LSW1 同理可得,给所有设备改名 二.VLAN LSW1 [LSW1]vlan ba 10 20 [LSW1]int g0/0/1 [LSW1-GigabitEthernet0/0/1]port link-type trunk [LSW1-GigabitEthernet0/0/1]port trunk allow-pass vlan 10 20 [LSW1-GigabitEthernet0/0/1]in…...
AI编程革命:重塑程序员未来(一)
AI编程时代到来AI不会让程序员消失,但会深刻重塑这个职业。当代码生成变得轻而易举,程序员 的角色将从“代码编写者”升级为“问题解决者”与“架构设计师”。未来的核心竞争力,在于 理解复杂业务、设计系统逻辑,并用人类独有的创…...
Claude Code 是怎么跑起来的:从 Agent Loop 理解代理循环实现
如果你已经会调用大模型、也知道 tool calling 和 agent 的基本概念,那接下来最值得看的问题通常不是“怎么再包一层 prompt”,而是:一个真正能跑任务的 agent,到底是怎么在代码里运转起来的。 这篇文章不从抽象定义讲起ÿ…...
Comsol 单孔激光烧蚀:探索微观世界的烧蚀奥秘
comsol单孔激光烧蚀 在材料加工等众多领域,激光烧蚀技术凭借其高精度、非接触等优势备受瞩目。而 Comsol 作为一款强大的多物理场仿真软件,为我们深入研究激光烧蚀过程提供了有力工具。今天就来聊聊 Comsol 单孔激光烧蚀那些事儿。 Comsol 仿真原理 激…...
抖音视频批量下载终极指南:5分钟掌握高效下载技巧
抖音视频批量下载终极指南:5分钟掌握高效下载技巧 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support. …...
当DWA遇上模糊控制:让路径规划更“聪明
基于改进动态窗口 DWA 模糊自适应调整权重的路径基于改进动态窗口 DWA 模糊自适应调整权重的路径规划算法 MATLAB 源码文档 《栅格地图可修改》 基本DWA算法能够有效地避免碰撞并尽可能接近目标点,但评价函数的权重因子需要根据实际情况进行调整。 为了提高DWA算法的…...
实战指南:利用快马平台为不同项目类型智能定制idea开发环境与工具链
今天想和大家分享一个实战经验:如何根据不同项目类型,快速定制专属的IDEA开发环境。作为开发者,我们经常需要切换不同技术栈,每次手动安装插件、配置SDK的过程实在太费时间。最近发现用InsCode(快马)平台可以智能解决这个问题&…...
Vivado IOBUF原语使用避坑:为什么你的双向端口信号总连不上?
Vivado IOBUF原语深度解析:从原理到实战的双向端口设计指南 在FPGA开发中,双向端口(inout)的设计一直是工程师们容易踩坑的领域。特别是当我们需要将独立的输入输出信号合并为顶层inout端口时,Vivado提供的IOBUF原语看…...
数学解题能力实测:通义千问QwQ-32B vs Claude 3.5 Sonnet,谁才是理科生最佳AI助手?
数学解题能力实测:通义千问QwQ-32B vs Claude 3.5 Sonnet,谁才是理科生最佳AI助手? 当一道复杂的AIME竞赛题摆在面前时,你会选择哪种AI助手?是擅长分步推导的开源新秀QwQ-32B,还是以逻辑严谨著称的Claude 3…...
FreeRTOS任务优先级怎么设?从智能健康助手项目看LVGL、传感器、看门狗任务的调度实战
FreeRTOS任务优先级设计实战:智能健康助手的调度艺术 在嵌入式系统开发中,任务优先级设置往往决定了整个系统的响应性和稳定性。我曾在一个智能健康监测设备项目中,面对LVGL界面、多传感器数据采集和系统监控等多任务协同工作的挑战…...
Kubernetes与网络管理最佳实践
Kubernetes与网络管理最佳实践 1. Kubernetes网络模型 Kubernetes网络模型定义了集群中Pod、Service和外部网络之间的通信规则,是集群网络管理的基础。 1.1 网络模型核心原则 Pod间通信:所有Pod可以直接通信,无需NATPod与Service通信…...
