C语言编译过程
C语言编译过程
- 1、C语言编译过程
- 2、单c文件编译实践
- 3、多c文件编译实践
- 4、define
- 4.1、不带参宏
- 4.2、带参宏
- 4.3、带参宏和带参函数的区别
- 5、选择性编译ifdef、ifndef、if
- 5.1、#ifdef
- 5.2、#ifndef
- 5.3、#if
- 6、静态库和动态链接库
- 6.1、静态库实践
- 6.1.1、将mylib.c制作成静态库
- 6.1.2、编译源程序
- 6.2、动态库实践
- 6.2.1、将mylib.c制作成动态链接库
- 6.2.2、动态链接库的使用
1、C语言编译过程
1、预编译
将 .c 中的头文件展开、宏展开。生成的文件是 .i 文件。预处理操作过程不会进行语法检查。
2、编译
将预处理之后的 .i 文件生成 .s 汇编文件。
3、汇编
将 .s 汇编文件生成 .o 目标文件。
4、链接
将 .o 文件链接成 可执行目标文件。
2、单c文件编译实践
hello.c文件
#include<stdio.h>int main() {printf("Hello World! \n");return 0;
}
Linux 下GCC 编译器编译过程
1、预处理
gcc -E hello.c -o hello.i
2、编译
gcc -S hello.i -o hello.s
3、汇编
gcc -c hello.s -o hello.o
4、链接
gcc hello.o -o hello

3、多c文件编译实践
#include<xxx.h>
// 用尖括号包含头文件,在系统指定的路径下找头文件
#include "xxx.h"
// 用双引号包含头文件,先在当前目录下找头文件,找不到,再到系统指定的路径下找。
注意:include 经常用来包含头文件,可以包含.c 文件,但是大家不要包含.c。
因为 include 包含的文件会在预编译被展开,如果一个.c 被包含多次,展开多次,会导致函数重复定义。所以不要包含.c 文件。
test.c文件
#include<stdio.h>
#include "max.h"
#include "min.h"int main() {int maxVal = max(1, 5);int minVal = min(1, 5);printf("最大值maxVal = %d;最小值minVal = %d \n", maxVal, minVal);return 0;
}
max.c文件
int max(int v1, int v2) {int z;if (v1>v2) {z = v1;}else {z = v2;}return z;
}
min.c文件
int min(int v1, int v2) {int z;if (v1 < v2) {z = v1;}else {z = v2;}return z;
}
max.h文件
extern int max(int v1, int v2);
min.h文件
extern int max(int v1, int v2);
gcc -E test.c -o test.i
gcc -S test.i -o test.s
gcc -c test.s -o test.ogcc -E max.c -o max.i
gcc -S max.i -o max.s
gcc -c max.s -o max.ogcc -E min.c -o min.i
gcc -S min.i -o min.s
gcc -c min.s -o min.ogcc test.o max.o min.o -o test


4、define
定义宏用 define 关键字,宏是在预编译的时候进行替换。
4.1、不带参宏
#define PI 3.1415926
在预编译的时候如果代码中出现了 PI
就用 3.1415926
去替换。
宏定义的好处:只要修改宏定义,其他地方在预编译的时候就会重新替换。
注意:宏定义后边不要加分号。
宏定义的作用范围:从定义的地方到本文件末尾。
如果想在中间终止宏的定义范围
//终止PI 的作用
#undef PI
4.2、带参宏
#define S(a,b) a*b
注意带参宏的形参 a 和 b 没有类型名:(注意歧义)
S(1,5)
即【1*5
】
S(3+4,3)
即【3+4 * 3
】
S((3+4),3)
即【(3+4)*3
】
4.3、带参宏和带参函数的区别
带参宏: 被调用多少次就会展开多少次,执行代码的时候没有函数调用的过程不需要压栈弹栈。所以带参宏,是浪费了空间,因为被展开多次,节省时间。
带参函数: 代码只有一份,存在代码段,调用的时候去代码段取指令,调用的时候要压栈弹栈。有个调用的过程。
带参函数是浪费了时间,节省了空间。
带参函数的形参是有类型的,带参宏的形参没有类型名。
5、选择性编译ifdef、ifndef、if
选择性编译都是在预编译阶段处理的事情。
5.1、#ifdef
#ifdef AAA代码段一
#else代码段二
#endif
#include<stdio.h>
#define AAAint main(int argc, char *argv[]){
#ifdef AAAprintf("Hello World!\n");
#elseprintf("Hello China!\n");
#endifreturn 0;
}
5.2、#ifndef
#ifndef AAA代码段一
#else代码段二
#endif
#ifndef
和 #ifdef
是一种互补。这种方法,经常用在防止头文件重复包含。
5.3、#if
如果表达式为真,编译第一段代码,否则编译第二段代码。
#if 表达式程序段一
#else程序段二
#endif
6、静态库和动态链接库
一、动态编译
动态编译使用的是动态库文件进行编译,默认使用的就是动态编译。
gcc hello.c -o hello1
二、静态编译
静态编译使用的静态库文件进行编译。
gcc -static hello.c -o hello2

三、静态编译和动态编译区别
1、使用的库文件的格式不一样:动态编译使用动态库,静态编译使用静态库。
2、静态编译要把静态库文件打包编译到可执行程序中。
3、动态编译不会把动态库文件打包编译到可执行程序中,它只是编译链接关系。
=== mytest.c ====================================
#include <stdio.h>
#include "mylib.h"int main(int argc, char* argv[]) {int a = 10, b = 20, max_num, min_num;max_num = max_fun(a, b);min_num = min_fun(a, b);printf("max_num = %d \n", max_num);printf("min_num = %d \n", min_num);return 0;
}=== mylib.c ====================================
int max_fun(int x, int y) {return (x > y) ? x : y;
}int min_fun(int x, int y) {return (x < y) ? x : y;
}=== mylib.h ====================================
#ifndef __MYLIB_H__
#define __MYLIB_H__
extern int max_fun(int x, int y);
extern int min_fun(int x, int y);
#endif
6.1、静态库实践
6.1.1、将mylib.c制作成静态库
gcc -c mylib.c -o mylib.o
ar rc libmylib.a mylib.o
注意:静态库文件 起名的时候必须以 lib
开头以 .a
结尾
6.1.2、编译源程序
方法1:在同一目录下编译
编译源程序命令:
gcc -static mytest.c libmylib.a -o mytest
方法2:可以指定头文件及库文件的路径
如将 libmylib.a
mylib.h
移动到 /root/staticlib
下
mv libmylib.a mylib.h /root/staticlib
编译源程序命令:
gcc mytest.c \
-static \
-o mytest \
-L /root/staticlib \
-l mylib \
-I /root/staticlib
注意:
-L
是指定库文件的路径
-l
指定找哪个库,指定的只要库文件名 lib
后面 .a
前面的部分
-I
指定头文件的路径
方法3:将库文件及头文件存放到系统默认指定路径
库文件 默认路径是 /lib
或者是 /usr/lib
头文件 默认路径是 /usr/include
mv libmylib.a /usr/lib
mv mylib.h /usr/include
编译源程序的命令
gcc mytest.c -o mytest -l mylib -static
6.2、动态库实践
6.2.1、将mylib.c制作成动态链接库
使用gcc 编译、制作动态链接库
gcc -shared mylib.c -o libmylib.so
注意:动态链接库文件 起名的时候必须以 lib
开头以 .so
结尾
6.2.2、动态链接库的使用
方法1:库函数、头文件均在当前目录下
gcc mytest.c libmylib.so -o mytest
export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH
此时就可以在执行了哦: ./mytest
方法2:库函数、头文件假设在 /opt/
目录
mv libmylib.so mylib.h /opt
gcc mytest.c -o mytest -L/opt -lmylib -I/opt编译通过,运行 mytest 时出错,编译时找到了库函数,但运行链接时找不到库,要把链接库文件所在目录加入默认搜索路径
export LD_LIBRARY_PATH=/opt:$LD_LIBRARY_PATH
此时就可以在执行了哦: ./mytest
方法3:库函数、头文件均在系统路径下
cp libmylib.so /usr/lib
cp mylib.h /usr/include
gcc mytest.c -o mytest -lmylib
如果出现如下错误,则添加查找路径,解决问题
[root@michael cc]# ./mytest
./mytest: error while loading shared libraries: libmylib.so: cannot open shared object file: No such file or directory解决方案:
export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH
此时就可以在执行了哦: ./mytest
注:
问:此时有个问题出现了?静态库 和 动态库 都在/usr/lib
下,那么默认链接的到底是动态库还是静态库呢?
答:当静态库与动态库重名时,系统会优先连接动态库,或者编译时加入-static
指定使用静态库。
相关文章:

C语言编译过程
C语言编译过程1、C语言编译过程2、单c文件编译实践3、多c文件编译实践4、define4.1、不带参宏4.2、带参宏4.3、带参宏和带参函数的区别5、选择性编译ifdef、ifndef、if5.1、#ifdef5.2、#ifndef5.3、#if6、静态库和动态链接库6.1、静态库实践6.1.1、将mylib.c制作成静态库6.1.2、…...
前端学习 ---常用标签
常用标签 1,文本标签 文本标签是双标签,自带加粗效果,有自己对应的文本大小,并且独占一行,有默认间距 一级标签:< h1 > < /h1 > 二级标签:< h2 > < /h2> 三级标签:&l…...

2023年PMP考试难不难?
整个考试的考察方向转向还是比较大的,基本上以“价值传递”和“以人为本”这两个出发点来考察项目经理所需要的能力。 1}新版提纲题目数量的变化 总题量从200道减少到180道,所以答题时间上相对变的宽裕一些。考试时间230分钟,中间有十分钟休…...

Netty 入门
文章目录一、概述1.1 Netty 是什么?1.2 Netty 的地位1.3 Netty 的优势二、Hello World2.1 目标2.2 服务器端2.3 客户端2.4 流程梳理三、组件3.1 EventLoop3.2 演示 NioEventLoop 处理 io 事件3.3 演示 NioEventLoop 处理普通任务3.4 演示 NioEventLoop 处理定时任务…...

收藏|一文掌握数据分析在企业的实际流程
一、数据分析概念 1.1 数据分析 是指用适当的统计分析方法对收集来的大量数据进行分析,将他们加以汇总和理解并消化,以求最大化地开发数据的功能,发挥数据的作用。 1.2 数据分析包括 描述性数据分析(初级数据分析)…...

100ask_imx6ull 输出PWM
查看PWM对应扩展板的引脚 100ask_imx6ul通过扩展板插槽来验证pwm波,所以这里通过扩展板的原理图及芯片手册可知,gpio4_io20,gpio4_io19分别对应着PWM8和PWM7。 设置设备树 打开官方NXP的工具i.MX pins v6工具,PWM7/PWM8的配置如…...
yolov5编译安卓APP:解决图像上全是检测框
yolov5编译安卓APP:解决图像上全是检测框前言一、第一个YOLOv5 APP1.参考链接2.详细说明3.APP检测时图像上全是框的解决方法二、第二个YOLOv5 APP1.参考链接2.详细说明3.APP检测时图像上全是框的解决方法三、其他1.APK打包2.修改APP图标与名字前言 YOLOv5编译安卓A…...
为什么我们需要地图?
想一想,武侠小说里面。一张藏宝图,引来江湖腥风血雨,要么是武功秘籍,要么是绝世宝剑,要么是富可敌国的财富,只要有了藏宝图,便可曲径通幽,到达彼岸。 由此可见,地图的重…...

攻防世界1.新手练习区
4.攻防世界1.新手练习区 1.view_source 访问url: http://111.200.241.244:48855/ 鼠标点击右键不起作用,F12审查元素 得到flag为cyberpeace{0f3a3e4ab8c8664f3cf40d4240ec7b53} 2.robots 访问url: http://111.200.241.244:34362/ rob…...

Python进阶篇(二)-- Django 深入模型
上一节提到了Django是基于MVC架构的Web框架,MVC架构追求的是“模型”和“视图”的解耦合。所谓“模型”说得更直白一些就是数据(的表示),所以通常也被称作“数据模型”。在实际的项目中,数据模型通常通过数据库实现持久…...

ABAP SALV实现弹出ALV选择
问题场景 需要弹出一个ALV并获取选择的数据 实现思路 跳转屏幕弹出ALV(通过SALV)弹出ALV(通过REUSE_ALV_POPUP_TO_SELECT) 实现效果 因为这里需要的是单选,所以没有多选列 实现代码 MODULE sel_zfretype INPUT.…...
git check-pick,git patch 与 git stash 详解
大家好,我是 17。 今天和大家聊一聊 git check-pick,git patch 与 git stash 的用法。 git cherry-pick 为什么要用 cherry-pick? 不适合 merge 的场景就可以考虑 cherry-pick。 试想下面这些场景 只想同步分支的部分提交。两个分支是两上完全独立…...

OA漏洞-到处搜集整理
一米OA getfile.jsp 任意文件读取漏洞 原文链接 漏洞复现 一米OA getfile.jsp 任意文件读取漏洞 一米OA协同办公系统,集成了OA办公自动化系统、手机客户端、专业报表工具,为全国千万企业用户提供全功能、性价比高的OA软件。一米OA getfile.jsp文件存在任意文件读取漏洞&am…...
web端接收读卡器卡片信息
项目背景 通过电脑连接的读卡器读取卡片信息,并由web页面接收和处理卡片信息。 读卡器抛出卡片信息流程 卡片贴近或放置到读卡器上读卡器解析卡片信息,并形成固定格式的字符串,包括的信息有:卡片写入的数据、卡片原数据&#x…...

BUUCTF-练习场-WEB-第一部分(8道)
[极客大挑战 2019]EasySQL 1payload:1 or 11#是闭合前面的查询语句,or 11恒成立,可以使用or句子绕过判断,#用于注释,注释后面的内容不再执行,所以该sql命令会返回表内所有内容,其实就是实现一个…...

Java Reflection 实战- Class类
Java Reflection 实战 - Class Java 反射使得在运行时检查类、接口、字段和方法成为可能,而不需要在编译时知道类、方法等的名称。也可以使用反射来实例化新对象、调用方法和获取/设置字段值。 Java反射的功能相当强大,可以说是非常有用。例如ÿ…...

背包问题理解思路(01背包、完全背包、分组背包)
这两天把经典的三个背包问题看了一下,网上大多文章是以代码和公式为主,因为平时没刷过算法题所以理解起来花了些时间,固写一篇文章记录理解思路,本文不包含代码实现(理解了思路代码实现应该是小问题,网上一…...

Mr. Cappuccino的第39杯咖啡——Kubernetes之深入理解Pod
Kubernetes之深入理解PodPod相关概念Pod详细配置清单Pod核心配置Pod基本配置1. 创建yaml文件2. 创建namespace并根据yaml文件创建资源3. 查看namespace下的pod列表以及pod的详细信息Pod中多个容器的名称和端口号不能相同Pod镜像拉取策略Pod环境变量Pod端口相关设置Pod资源相关配…...

SqlSession 和 SqlSessionTemplate 简单使用及注意事项
1、SqlSession 简单使用 先简单说下 SqlSession 是什么?SqlSession 是对 Connection 的包装,简化对数据库操作。所以你获取到一个 SqlSession 就相当于获取到一个数据库连接,就可以对数据库进行操作。 SqlSession API 如下图示:…...

1. QSaveFile和QFile的简单使用
1. 说明 QSaveFile和QFile两个类都是用来操作文件的,区别在于QSaveFile在对文件进行写入时有一种保护机制,再写入出错时,不会对源文件中的内容进行操作。该类在执行写操作时,会先将内容写入到一个临时文件中,如果没有…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...