C语言编译过程

news2024/10/2 6:26:07

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.o

gcc -E max.c -o max.i
gcc -S max.i -o max.s
gcc -c max.s -o max.o

gcc -E min.c -o min.i
gcc -S min.i -o min.s
gcc -c min.s -o min.o

gcc 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 AAA

int main(int argc, char *argv[]){
#ifdef AAA
	printf("Hello World!\n");
#else
	printf("Hello China!\n");
#endif
	return 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 指定使用静态库。

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

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

相关文章

Baklib知识库管理平台,协助组织提升知识管理水平

随着信息时代和知识经济时代的到来&#xff0c;企业内部信息资料繁多冗杂&#xff0c;知识管理逐渐成为各大企业的重要工作之一&#xff0c;企业管理者无不感受到巨大的压力&#xff0c;怎么样将知识进行有效的管理&#xff0c;成为一个难点&#xff0c;并且随着信息不断的更迭…

Java企业级信息系统开发学习笔记(1)初探Spring与骑士傻龙实例

该文章主要为完成实训任务&#xff0c;详细实现过程及结果见【http://t.csdn.cn/iK3aM】 文章目录1. 创建Maven项目2. 添加Spring依赖3. 创建杀龙任务4. 创建勇士类5. 采用传统的方式6. 采用Spring容器让勇敢骑士完成杀龙任务6.1 创建日志属性文件6.2 创建Spring配置文件6.3 在…

CobaltStrike上线微信通知

CobaltStrike上线微信通知 利用pushplus公众号&#xff08;每天免费发送200条消息&#xff09; http://www.pushplus.plus/push1.html 扫码登录后需要复制token 可以测试一下发送一下消息&#xff0c;手机会受到如下消息。可以在微信提示里将消息免打扰关闭&#xff08;默认…

分布式光伏储能系统的优化配置方法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

期末复习提纲

复习提纲 题型&#xff1a;编程题3题&#xff0c;综合题4题。 一、编程题&#xff1a; 1、链表的类型定义&#xff1b;邻接矩阵表示图的类型定义&#xff1b;链接表表示图的类型定义&#xff1b;vector数组表示图的定义和使用方法。 2、链表中结点的插入和删除操作&#xff…

linux高级命令之编辑器 vim

编辑器 vim学习目标能够说出vim的三种工作模式能够说出vim对应复制和粘贴命令1. vim 的介绍vim 是一款功能强大的文本编辑器&#xff0c;也是早年 Vi 编辑器的加强版&#xff0c;它的最大特色就是使用命令进行编辑&#xff0c;完全脱离了鼠标的操作。2. vim 的工作模式命令模式…

2023想转行软件测试的看过来,你想要了解的薪资、前景、岗位方向、学习路线都讲明白了

在过去的一年中&#xff0c;软件测试行业发展迅速&#xff0c;随着数字化技术应用的广泛普及&#xff0c;业界对于软件测试的要求也在持续迭代与增加。 同样的&#xff0c;有市场就有需求&#xff0c;软件测试逐渐成为企业中不可或缺的岗位&#xff0c;作为一个高薪又需求广的…

怎么解密MD5,常见的MD5解密方法,一看就会

MD5是一种被广泛使用的密码散列函数&#xff0c;曾在计算机安全领域使用很广泛&#xff0c;但是也因为它容易发生碰撞&#xff0c;而被人们认为不安全。那么&#xff0c;MD5应用场景有哪些&#xff0c;我们怎么解密MD5&#xff0c;本文将带大家了解MD5的相关知识&#xff0c;以…

Laravel创建定时任务

创建一个任务&#xff0c;创建成功后会在App/Console/Commands中生成一个以Test命名的文件&#xff0c;我们可以在这里面写我们的任务指令。 php artisan make:command Test 运行这个定时任务 run 是运行一次&#xff0c;我们可以用来测试是否成功&#xff0c;work是一直运行&a…

Jenkins的使用教程

介绍&#xff1a; Jenkins是一个开源软件项目&#xff0c;是基于Java开发的一种持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件的持续集成变成可能。 目的: 最重要目的就是把原来分散在各个机器上繁杂的工作全部…

hadoop高可用搭建

修改计算机名称 //修改计算机名称 [rootlocalhost ~]# hostnamectl set-hostname ant150//快速生效 [rootlocalhost ~]# bash 主机名称映射 [rootant150 ~]# vim /etc/hosts 192.168.153.150 ant150 192.168.153.151 ant151 192.168.153.152 ant152 192.168.153.153 ant153 …

数据分析-深度学习 Tensorflow Day6

我们需要解决的问题&#xff1a;1&#xff1a; 什么是bp 神经网络&#xff1f;2&#xff1a;理解bp神经网络需要哪些数学知识&#xff1f;3&#xff1a;梯度下降的原理4: 激活函数5&#xff1a;bp的推导。1.什么是bp网络&#xff1f;引用百度知道回复&#xff1a;“我们最常用的…

【mmrotate】旋转目标检测之训练DOTA数据集

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 mmrotate训练DOTA数据集记录 1. 正文 1.1 数据准备 数据介绍部分&#xff0c;参考DOTA数据介绍&#xff0c;官方提供了裁剪工具development kit。这里…

LINUX内核链表

LINUX内核链表 一、传统链表的缺陷 传统的双向循环链表概念简单&#xff0c;操作方便&#xff0c;但存在有致命的缺陷&#xff0c;用一句话来概括就是&#xff1a; 每一条链表都是特殊的&#xff0c;不具有通用性。换句话说&#xff0c;对于每一种不同的数据&#xff0c;所构…

java对象克隆和面向对象的设计原则

java进阶注解内置注解元注解自定义注解对象克隆浅克隆深克隆java设计模式建模语言类之间的关系依赖关系关联关系单向关联双向关联自关联聚合关系组合关系继承关系实现关系面向对象设计原则单一职责开闭原则里氏替换原则依赖倒置接口隔离迪米特原则组合/聚合复用原则注解 java注…

关于ucharts在小程序中的使用

项目添加组件 画图之前&#xff0c;首先需要引入ucharts组件&#xff0c;引入链接https://ext.dcloud.net.cn/plugin?id271。 点击下图中红色方框内容&#xff1a; 导入完成后&#xff0c;与uni其他组件一样&#xff0c;无需引入&#xff0c;直接使用即可。 使用组件 uchar…

jhipster自动生成java代码的方法

一、前言 java springboot后台项目用到了jpa查询数据库&#xff0c;还用到了jhipster&#xff0c;这个东西可以自动生成基础的Controller、Service、Dao、JavaBean等相关代码&#xff0c;减少重复开发。 在此总结下使用方法。 二、jhipster自动生成java代码的方法 1.需要先…

KDHX-8700无线高压核相相序表

一、产品简介 KDHX-8700无线高压核相相序表&#xff08;以下简称“仪器”&#xff09;用于测定三相线相序、检测环网或双电源电力网闭环点断路器两侧电源是否同相。在闭环两电源之前一定要进行核相操作&#xff0c;否则可能发生短路。仪器适用于380V&#xff5e;35kV交流输电线…

JavaScript void

文章目录JavaScript voidjavascript:void(0) 含义href"#"与href"javascript:void(0)"的区别JavaScript void javascript:void(0) 含义 我们经常会使用到 javascript:void(0) 这样的代码&#xff0c;那么在 JavaScript 中 javascript:void(0) 代表的是什么…

RTSP协议交互时TCP/UDP的区别 以及视频和音频的区别 以及H264/H265的区别

经过这几天的调试 一个功能简单的 RTSP服务端已经实现了 支持TCP/UDP 支持H264 H265 支持同时传输 AAC音频 记录下 交互时需要注意的地方 1.OPTIONS 都一样 如下&#xff1a;左箭头内是客户端发给服务端 箭头内是服务端回给客户端 2.DESCRIBE 目前的流是包含视频和AAC音频…