linux gcc

一、常用编译选项

  1. 基本编译
    gcc [input].c -o [output]
    示例

    gcc hello.c -o hello  # 将 hello.c 编译为可执行文件 hello
    ./hello               # 运行程序
  2. 分步编译

    • 预处理:-E(生成 .i 文件)
      gcc -E hello.c -o hello.i
    • 编译为汇编:-S(生成 .s 文件)
      gcc -S hello.i -o hello.s
    • 汇编为目标文件:-c(生成 .o 文件)
      gcc -c hello.s -o hello.o
    • 链接为可执行文件:
      gcc hello.o -o hello
  3. 调试信息
    -g 选项生成带调试信息的文件(供 GDB 使用):

    gcc -g test.c -o test_debug
  4. 优化选项
    -O1-O2-O3 表示优化级别(-O2 最常用):

    gcc -O2 main.c -o optimized_program
  5. 警告选项

    • -Wall 启用所有常见警告
    • -Werror 将警告视为错误
    gcc -Wall -Werror strict_code.c -o strict_program
  6. 链接库文件

    • -l 指定库名(如数学库 -lm
    • -L 指定库文件路径
    gcc calc.c -lm -L/usr/local/lib -o calc

二、示例场景

1. 编译多文件项目
# 编译两个文件并链接
gcc main.c utils.c -o app
2. 生成静态库
# 1. 编译为 .o 文件
gcc -c mylib.c -o mylib.o
# 2. 打包为静态库
ar rcs libmylib.a mylib.o
# 3. 使用静态库
gcc main.c -L. -lmylib -o static_app
3. 生成动态库(共享库)
# 1. 编译为位置无关代码(-fPIC)
gcc -fPIC -c mylib.c -o mylib.o
# 2. 生成动态库(-shared)
gcc -shared mylib.o -o libmylib.so
# 3. 使用动态库(需设置库路径)
gcc main.c -L. -lmylib -o dynamic_app
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH  # 临时添加库路径

三、C语言是如何编译的

1. 预处理

类比:准备食材

想象你在做一道复杂的菜,首先你需要把所有的食材准备好,比如切菜、洗菜、调味等。预处理阶段就像是这个准备食材的过程。

具体过程

预处理器(cpp)会处理源代码文件中的预处理指令,比如 #include#define 和 #ifdef 等。它会将这些指令替换成实际的代码或数据。

  • #include​:将指定的头文件内容插入到当前文件中。
  • #define​:定义宏,替换代码中的宏定义。
  • #ifdef / #ifndef​:条件编译,根据条件决定是否包含某段代码。

示例

#include <stdio.h>
#define PI 3.14159int main() {printf("The value of PI is %f", PI);return 0;
}

预处理后,#include <stdio.h> 会被替换成 stdio.h 文件的内容,PI 会被替换成 3.14159

2. 编译

类比:编写食谱

现在你已经准备好了食材,接下来你需要编写一个详细的食谱,告诉厨师每一步该怎么做。编译阶段就像是这个编写食谱的过程。

具体过程

编译器(gcc)会将预处理后的源代码转换成汇编代码。这个过程会检查语法错误、类型检查等。

  • ​语法检查​​:确保代码符合C语言的语法规则。
  • ​类型检查​​:确保变量和函数的类型使用正确。

示例

预处理后的代码会被编译成类似以下的汇编代码(具体内容取决于编译器和平台):

main:push    rbpmov     rbp, rspsub     rsp, 16mov     edi, OFFSET FLAT:.LC0call    puts@PLTmov     eax, 0leaveret

3. 汇编

类比:将食谱翻译成操作步骤

现在你已经有了详细的食谱,接下来需要将这些食谱翻译成具体的操作步骤,让厨师可以一步步执行。汇编阶段就像是这个翻译过程。

具体过程

汇编器(as)会将汇编代码转换成机器码,生成目标文件(.o 文件)。这个过程不会进行任何优化,只是简单地将汇编指令转换成机器码。

示例

上面的汇编代码会被转换成机器码,生成一个目标文件 main.o

4. 链接

类比:将多个菜谱合并成一本完整的烹饪书

现在你已经有了每道菜的具体操作步骤,接下来需要将这些步骤合并成一本完整的烹饪书,确保所有的步骤和食材都能协调工作。链接阶段就像是这个合并过程。

具体过程

链接器(ld)会将多个目标文件和库文件合并成一个可执行文件。这个过程会解析所有的符号引用,确保每个函数和变量的调用都能找到正确的定义。

  • ​符号解析​​:确保每个函数和变量的调用都能找到正确的定义。
  • ​重定位​​:将符号的地址修正为最终的内存地址。

假设你有两个源文件 main.c 和 utils.c,编译后会生成 main.o 和 utils.o。链接器会将这两个目标文件合并成一个可执行文件 program

总结

  1. ​预处理​​:准备食材,处理 #include#define 等指令。
  2. ​编译​​:编写食谱,将预处理后的代码转换成汇编代码。
  3. ​汇编​​:将食谱翻译成操作步骤,生成目标文件。
  4. ​链接​​:合并多个菜谱,生成最终的可执行文件。

5.函数库

静态库

定义​​:静态库是将一系列的目标文件(.o 文件)打包成一个单独的文件,在编译链接时,链接器会把静态库中被程序使用的代码直接复制到最终的可执行文件中。静态库的文件扩展名通常是 .a

静态连接在静态连接中,编译器和链接器在编译阶段就把程序所需要使用的库代码(静态库)直接合并到最终生成的可执行文件中。

  • ​创建静态库​​:首先要有多个目标文件。假设我们有两个源文件 add.c 和 sub.c,分别实现加法和减法功能。
// add.c
int add(int a, int b) {return a + b;
}// sub.c
int sub(int a, int b) {return a - b;
}

使用 `gcc` 编译这两个源文件生成目标文件:

gcc -c add.c sub.c

然后使用 `ar` 工具创建静态库:

ar rcs libmath.a add.o sub.o

这里 ar 是归档工具,r 表示将目标文件插入到归档文件中,c 表示如果归档文件不存在则创建它,s 表示写入一个目标文件索引。

 这样来使用静态库

gcc main.c -L. -lmath -o main

-L. 表示在当前目录下查找库文件,-lmath 表示链接名为 libmath.a 的静态库(注意,-l 后面跟的是库名去掉 lib 前缀和 .a 后缀)。 

优点
  • ​独立性​​:可执行文件包含了静态库的所有代码,不依赖外部的库文件,移植方便。
  • ​性能​​:由于代码已经直接嵌入到可执行文件中,运行时不需要额外的加载时间,执行效率较高。
缺点
  • ​文件体积大​​:每个使用静态库的可执行文件都会包含一份库代码的副本,会导致可执行文件体积变大。
  • ​更新困难​​:如果静态库有更新,所有使用该库的可执行文件都需要重新编译链接。
动态库

定义​​:动态库是在程序运行时才被加载到内存中供程序使用的库。多个程序可以共享同一个动态库的内存副本。是C/C++或者其他第三方软件提供的所有方法的集合,被所有程序以链接的方式关联起来。动态库的文件扩展名通常是 .so

动态链接在动态连接中,编译阶段只是记录程序需要使用哪些动态库(.so 文件),然后再需要时加载,并不会把库代码复制到可执行文件中。

  • 创建动态库​​:同样使用之前的 add.c 和 sub.c 源文件,先编译成目标文件:
gcc -c -fPIC add.c sub.c

-fPIC 表示生成位置无关代码,这是创建动态库所必需的。
使用 gcc 创建动态库:

gcc -shared -o libmath.so add.o sub.o

-shared 表示生成共享库。

​使用动态库​​:

gcc main.c -L. -lmath -o main

编译命令和静态库类似,但在运行可执行文件时,需要确保系统能找到动态库。可以通过设置 LD_LIBRARY_PATH 环境变量来指定动态库的搜索路径:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./main
优点
  • ​节省内存​​:多个程序可以共享同一个动态库的内存副本,减少了内存的使用。
  • ​更新方便​​:如果动态库有更新,只需要替换动态库文件,不需要重新编译使用该库的所有程序。
缺点
  • ​依赖问题​​:可执行文件依赖于外部的动态库文件,如果动态库文件丢失或版本不兼容,程序可能无法正常运行。
  • ​加载时间​​:程序运行时需要加载动态库,会有一定的加载时间开销。

 

注意:linux系统中认为后缀无意义,但不是代表gcc认为后缀无意义,也就是说我们后缀不对的话gcc编译会出错的。

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

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

相关文章

若依框架二次开发——RuoYi-AI 集成本地大模型

文章目录 前提条件1. RuoYi-AI 已成功部署并运行2. Ollama 本地大模型已安装1. 配置本地大模型2. 切换至本地模型3. 开始对话总结本文将详细介绍如何在 RuoYi-AI 中集成本地 Ollama 大模型,使系统能够在 离线环境 下提供智能对话能力。 前提条件 在开始集成本地大模型之前,…

Flask学习笔记 - 模板渲染

Flask 模板渲染 模板是包含占位符的 HTML 文件 Flask 使用 Jinja2 模板引擎来处理模板渲染。模板渲染允许你将动态内容插入到 HTML 页面中&#xff0c;使得应用能够生成动态的网页内容。 创建模板&#xff1a;将 HTML 文件放在 templates 文件夹中&#xff0c;使用 Jinja2 占…

解码 from XXX import * - 导入的真相

文章目录 前言一、 什么是 from XXX import *?二、基本用法:导入的实际效果三、默认行为:无 __all__ 的情况四、与直接运行 XXX.py 的对比示例模块使用 from XXX import *直接运行 python example.py关键差异五、为什么需要注意 from XXX import *?最佳实践六、实际应用场景…

JavaScript 中常见的鼠标事件及应用

JavaScript 中常见的鼠标事件及应用 在 JavaScript 中&#xff0c;鼠标事件是用户与网页进行交互的重要方式&#xff0c;通过监听这些事件&#xff0c;开发者可以实现各种交互效果&#xff0c;如点击、悬停、拖动等。 在 JavaScript 中&#xff0c;鼠标事件类型多样&#xff0…

Nacos注册中心AP模式核心源码分析(单机模式)

文章目录 概述一、客户端启动主线流程源码分析1.1、客户端与Spring Boot整合1.2、注册实例&#xff08;服务注册&#xff09;1.3、发送心跳1.4、拉取服务端实例列表&#xff08;服务发现&#xff09; 二、服务端接收请求主线流程源码分析2.1、接收注册请求2.1.1、初始化注册表2…

prism WPF 模块

模块 DLL ModuleA 和 ModuleB 都要安装 Prism.Unity 引用方式1 项目引用 直接 在引用中添加项目引用 App.xaml.cs 添加模块 ConfigureModuleCatalog using ModuleA; using ModuleB; using Prism.Ioc; using Prism.Modularity; using Prism.Unity; using PrismWpfApp.ViewMo…

CSS:换行与不换行

一、CSS 不允许换行 在 CSS 中&#xff0c;有几种方法可以控制文本不换行&#xff1a; 1. 使用 white-space 属性 .no-wrap {white-space: nowrap; } white-space: nowrap; 会强制文本在一行显示&#xff0c;不换行。 2. 使用 overflow 和 text-overflow 通常与 white-sp…

JavaScript BOM、事件循环

目录 BOM&#xff08;浏览器对象模型&#xff09; 一、window 对象 1. 窗口控制 2. 定时器 二、location 对象 三、navigator 对象 四、history 对象 五、screen 对象 六、本地存储 1. localStorage 2. sessionStorage 七、BOM 应用场景 八、总结 JavaScript 执行…

k8s运维面试总结(持续更新)

一、你使用的promethues监控pod的哪些指标&#xff1f; CPU使用率 内存使用率 网络吞吐量 磁盘I/O 资源限制和配额&#xff1a;Prometheus可以监控Pod的资源请求和限制&#xff0c;确保它们符合预设的配额&#xff0c;防止资源过度使用。具体指标如container_spec_cpu_quota用于…

ubuntu20.04升级成ubuntu22.04

命令行 sudo do-release-upgrade 我是按提示输入y确认操作&#xff0c;也可以遇到配置文件冲突时建议选择N保留当前配置

Cortex-M​ 函数调用的入栈与出栈操作

在 ARM Cortex-M 系列单片机中,普通C函数调用的入栈(压栈)和出栈操作通常由编译器编译后生成的代码管理,而硬件仅负责部分关键操作。以下是详细分析: 1. 函数调用与返回的核心机制 (1) 硬件自动完成的部分 返回地址的保存: 当通过 BL(Branch with Link)或 BLX 指令调用…

DeepSeek能否用于对话系统(Chatbot)?技术解析与应用实例!

引言&#xff1a;Chatbot 的进化与挑战 你有没有发现&#xff0c;现在的AI聊天机器人越来越聪明了&#xff1f;无论是客服助手、智能语音设备&#xff0c;还是社交媒体上的自动回复&#xff0c;Chatbot&#xff08;对话系统&#xff09;已经渗透到我们生活的方方面面。但问题是…

多表查询的多与一

1.查寻表需要的条件 1.1.首先我们要了解查询表有哪些 1.1.1.多对一 多对一就是一个年表拥有例外一个表的多条数据 一个表对应立一个表的多条数据&#xff0c;另一个表对应这个表的多条数据 这个点被称为多对一 1.1.2.多对多 多对多简单来说就是需要一个中间商 中间商就…

配置文件、Spring日志

SpringBoot配置⽂件 SpringBoot⽀持并定义了配置⽂件的格式, 也在另⼀个层⾯达到了规范其他框架集成到SpringBoot的 ⽬的. 很多项⽬或者框架的配置信息也放在配置⽂件 中, ⽐如: 项⽬的启动端⼝ 数据库的连接信息(包含⽤⼾名和密码的设置) 第三⽅系统的调⽤密钥等信息 ⽤…

嵌入式——Linux系统的使用以及编程练习

目录 一、Linux的进程、线程概念 &#xff08;一&#xff09;命令控制进程 1、命令查看各进程的编号pid 2、命令终止一个进程pid 二、初识Linux系统的虚拟机内存管理 &#xff08;一&#xff09;虚拟机内存管理 &#xff08;二&#xff09;与STM32内存管理对比 三、Lin…

Springcache+xxljob实现定时刷新缓存

目录 SpringCache详解 SpringCache概述 核心原理 接口抽象与多态 AOP动态代理 核心注解以及使用 公共属性 cacheNames KeyGenerator&#xff1a;key生成器 key condition&#xff1a;缓存的条件&#xff0c;对入参进行判断 注解 xxl-job详解 SpringcacheRedis实现…

前端Uniapp接入UviewPlus详细教程!!!

相信大家在引入UviewPlusUI时遇到很头疼的问题&#xff0c;那就是明明自己是按照官网教程一步一步的走&#xff0c;为什么到处都是bug呢&#xff1f;今天我一定要把这个让人头疼的问题解决了&#xff01; 1.查看插件市场 重点&#xff1a; 我们打开Dcloud插件市场搜素uviewPl…

vector的介绍与代码演示

由于以后我们写OJ题时会经常使用到vector&#xff0c;所以我们必不可缺的是熟悉它的各个接口。来为我们未来作铺垫。 首先&#xff0c;我们了解一下&#xff1a; https://cplusplus.com/reference/vector/ vector的概念&#xff1a; 1. vector是表示可变大小数组的序列容器…

ZLMediaKit 源码分析——[5] ZLToolKit 中EventPoller之延时任务处理

系列文章目录 第一篇 基于SRS 的 WebRTC 环境搭建 第二篇 基于SRS 实现RTSP接入与WebRTC播放 第三篇 centos下基于ZLMediaKit 的WebRTC 环境搭建 第四篇 WebRTC学习一&#xff1a;获取音频和视频设备 第五篇 WebRTC学习二&#xff1a;WebRTC音视频数据采集 第六篇 WebRTC学习三…

【零基础入门unity游戏开发——2D篇】SortingGroup(排序分组)组件

考虑到每个人基础可能不一样&#xff0c;且并不是所有人都有同时做2D、3D开发的需求&#xff0c;所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】&#xff1a;主要讲解C#的基础语法&#xff0c;包括变量、数据类型、运算符、…