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

    extern 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 生成的可执行文件名

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

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

相关文章

OpenSSL 使用AES对文件加解密

AES&#xff08;Advanced Encryption Standard&#xff09;是一种对称加密算法&#xff0c;它是目前广泛使用的加密算法之一。AES算法是由美国国家标准与技术研究院&#xff08;NIST&#xff09;于2001年发布的&#xff0c;它取代了原先的DES&#xff08;Data Encryption Stand…

JVM GC算法

一, 垃圾回收分类: 按线程数分&#xff0c;可以分为串行垃圾回收器和并行垃圾回收器。 按工作模式分&#xff0c;可以分为并发垃圾回收器和独占式垃圾回收器 按碎片处理方式分&#xff0c;可以分为压缩式垃圾回收器和非压缩式垃圾回收器按工作的内存区间分&#xff0c;又可分为…

2000-2021年上市公司过度负债数据

2000-2021年上市公司过度负债数据 1、时间&#xff1a;2000-2021年 2、指标&#xff1a; 证券代码、证券简称、会计期间、上市日期、行业代码、行业名称、是否剔除ST或*ST股、是否剔除当年新上市、已经退市或被暂停退市的公司、产权性质、盈利能力、杠杆率行业中位数、成长性…

数据结构与算法-静态查找表

&#x1f31e; “清醒 自律 知进退&#xff01;” 查找 &#x1f388;1.查找的相关概念&#x1f388;2.静态查找表&#x1f52d;2.1静态查找表的类定义&#x1f52d;2.2顺序查找&#x1f52d;2.3二分查找&#x1f50e;二分查找例题 &#x1f52d;2.4分块查找&#x1f52d;2.5三…

oracle sql相关语法

SQL*PLUS 在SQL*PLUS执行&#xff0c;会在执行后显示查询的执行计划和统计信息 SET AUTOTRACE ON;SELECT * FROM your_table WHERE column_name value;SET AUTOTRACE OFF;PLSQL PLSQL查询sql界面&#xff0c;鼠标右键&#xff0c;点击执行计划&#xff0c;会出现sql的执行计…

鸿蒙原生应用/元服务开发-AGC分发如何生成密钥和和证书请求文件

HarmonyOS通过数字证书&#xff08;.cer文件&#xff09;和Profile文件&#xff08;.p7b文件&#xff09;等签名信息来保证应用的完整性&#xff0c;应用如需上架到华为应用市场必须通过签名校验。因此&#xff0c;开发者需要使用发布证书和Profile文件对应用进行签名后才能发布…

04_Flutter自定义Slider滑块

04_Flutter自定义Slider滑块 一.Slider控件基本用法 Column(mainAxisAlignment: MainAxisAlignment.start,children: <Widget>[Text("sliderValue: ${_sliderValue.toInt()}"),Slider(value: _sliderValue,min: 0,max: 100,divisions: 10,thumbColor: Colors.…

Java研学-配置文件

一 配置文件 1 作用–解决硬编码的问题 在实际开发中,有时将变量的值直接定义在.java源文件中;如果维护人员想要修改数据,无法完成(因为没有修改权限),这种操作称之为硬编码 2 执行原理: 将经常需要改变的数据定义在指定类型的文件中,通过java代码对指定的类型的文件进行操作…

软件测试框架实战:Python+Slenium搭建Web自动化测试框架全教程

PythonSelenium是一种流行的Web自动化测试框架&#xff0c;可以模拟真实的用户操作&#xff0c;对网页进行功能和样式的验证。要通过selenium测试网页&#xff0c;需要以下几个步骤&#xff1a; 安装selenium库和浏览器驱动 。使用selenium提供的方法来控制浏览器窗口大小、后…

【NeurIPS 2023】PromptIR: Prompting for All-in-One Blind Image Restoration

PromptIR: Prompting for All-in-One Blind Image Restoration&#xff0c; NeurIPS 2023 论文&#xff1a;https://arxiv.org/abs/2306.13090 代码&#xff1a;https://github.com/va1shn9v/promptir 解读&#xff1a;即插即用系列 | PromptIR&#xff1a;MBZUAI提出一种基…

非得让你会之MyBatis插件与Java动态代理

引言 咱们今天聊聊Java动态代理&#xff0c;这东西在开发中真的太常见了。比如Spring AOP、RPC&#xff0c;它们都离不开动态代理。然后&#xff0c;咱们再来说说MyBatis插件&#xff0c;这可是MyBatis框架中的一个超实用的功能&#xff0c;它就像是给MyBatis加了个“超能力”…

基于WebSocket实现客户聊天室

目录 一、实现聊天室原理 二、聊天室前端代码 三、聊天室后端代码&#xff08;重点&#xff09; 四、聊天室实现效果展示 一、实现聊天室原理 1.1 介绍websocket协议 websocket是一种通信协议&#xff0c;再通过websocket实现弹幕聊天室时候&#xff0c;实现原理是客户端首…

Unity Image - 镜像

1、为什么要使用镜像 在游戏开发过程中&#xff0c;我们经常会为了节省 美术图片资源大小&#xff0c;美术会将两边相同的图片进行切一半来处理。如下所示一个按钮 需要 400 * 236&#xff0c;然而美术只需要切一张 74*236的大小就可以了。这样一来图集就可以容纳更多的图片。…

HarmonyOs 4 (一) 认识HarmonyOs

目录 一 HarmonyOs 背景1.1 发展时间线1.2 背景分析1.2.1 新场景1.2.2 新挑战1.2.3 鸿蒙生态迎接挑战 二 HarmonyOS简介2.1 OpenHarmony2.2 HarmonyOS Connect2.3 HarmonyOS Next**2.4 ArkTS &#xff08;重点掌握&#xff09;****2.5 ArkUI** 三 鸿蒙生态应用核心技术理念**3.…

SmartSoftHelp8,数据库字段详细文档自动生成工具

数据库开发文档自动生成 包括数据库设计详细信息&#xff1a; 数据库字段名称&#xff0c;数据类型&#xff0c;大小&#xff0c;是否主键&#xff0c;说明等 一键自动生成开发需求文档 导出html 格式方便查询 下载地址 https://pan.baidu.com/s/1zBgeYsqWnSlNgiKPR2lUYg…

Spring---更简单的存储和读取对象

文章目录 存储Bean对象配置扫描路径添加注解存储Bean对象使用类注解为什么需要五个类注解呢&#xff1f;Bean命名规则 使用方法注解重命名Bean 读取Bean对象属性注入Setter注入构造方法注入注入多个相同类型的BeanAutowired vs Resource 存储Bean对象 配置扫描路径 注&#xf…

maven下载和安装

maven下载和安装 一、概述 Maven是一个项目管理工具&#xff0c;它包含了一个项目对象模型 (Project Object Model)&#xff0c;一组标准集合&#xff0c;一个项目生命周期(Project Lifecycle)&#xff0c;一个依赖管理系统(Dependency Management System)&#xff0c;和用来…

conda环境下 ERROR: CMake must be installed to build dlib问题解决

1 问题描述 在构建video_retalking项目过程中&#xff0c;使用命令安装依赖包时&#xff0c;运行依赖安装命令&#xff1a; pip install -r requirements.txt 出现如下错误&#xff1a; Building wheels for collected packages: face-alignment, dlib, ffmpy, futureBuil…

【HuggingFace Transformer库学习笔记】基础组件学习:Tokenizer

基础组件——Tokenizer &#xff08;1&#xff09;模型加载 from transformers import AutoTokenizersen "弱小的我也有大梦想!" # 从HuggingFace加载&#xff0c;输入模型名称&#xff0c;即可加载对于的分词器 tokenizer AutoTokenizer.from_pretrained("m…

〖大前端 - 基础入门三大核心之JS篇㊸〗- DOM事件对象及它的属性

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;不渴望力量的哈士奇(哈哥)&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xf…