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在对文件进行写入时有一种保护机制,再写入出错时,不会对源文件中的内容进行操作。该类在执行写操作时,会先将内容写入到一个临时文件中,如果没有…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
