『C/C++养成计划』C++中的静态库和动态库|GCC|Makefile|CMake学习

news2024/11/25 8:19:36
C++中的静态库和动态库|GCC|Makefile|CMake学习!

文章目录

  • 一. 什么是库
  • 二. 静态库
    • 1.1. 静态库生成
    • 1.2. 静态库制作举例
      • 1.2.1 准备测试程序
      • 1.2.2 生成静态库
    • 1.3. 静态库的使用
  • 三. 动态库
    • 3.1. 为什么需要动态库
    • 3.2. 生成动态链接库
    • 3.3. 动态库制作举例
    • 3.4. 动态库的使用
    • 3.4. 解决动态库无法加载问题
      • 3.4.1. 库的工作原理
      • 3.4.2. 动态链接器
      • 3.4.3. 解决方案
      • 3.4.4. 验证
  • 补充:GCC学习
    • 1.1 gcc 工作流程|常用命令|多文件编译|gcc和g++
  • 补充:Makefile学习
    • 1.1 规则|工作原理|变量|模式匹配|函数
  • 补充:CMake学习
    • 1.1 CMake 概述|CMake的使用|预定义宏|嵌套的CMake|流程控制
  • 参考文献

一. 什么是库

  • 库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。所谓静态、动态是指链接。回顾一下,将一个程序编译成可执行程序的步骤:

在这里插入图片描述

二. 静态库

  • 之所以成为【静态库】,是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接
  • 试想一下,静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.o文件格式相似。其实一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。静态库特点总结:
  • 静态库对函数库的链接是放在编译时期完成的。
  • 程序在运行时与函数库再无瓜葛,移植方便。
  • 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。
  • 在 Linux 中静态库由程序 ar(gcc工具集里的) 生成,现在静态库已经不像之前那么普遍了,这主要是由于程序都在使用动态库。关于静态库的命名规则如下:
  • 在 Linux 中静态库以 lib 作为前缀,以.a 作为后缀,中间是库的名字自己指定即可,即: libxxx.a
  • 在 Windows 中静态库一般以 lib 作为前缀,以 lib 作为后缀,中间是库的名字需要自己指定,即: libxxx.lib

1.1. 静态库生成

  • 生成静态库,需要先对源文件进行汇编操作 (使用参数 -c) 得到二进制格式的目标文件 (.o 格式), 然后在通过 ar 工具将目标文件打包就可以得到静态库文件了 (libxxx.a)。
  • 使用 ar 工具创建静态库的时候需要三个参数:

在这里插入图片描述

在这里插入图片描述

  • 生成静态链接库的具体步骤如下:
  • 1. 需要将源文件进行汇编,得到 .o 文件,需要使用参数 -c
# 执行如下操作, 默认生成二进制的 .o 文件
# -c 参数位置没有要求
gcc 源文件(*.c) -c	
  • 2. 将得到的 .o 进行打包,得到静态库
ar rcs 静态库的名字(libxxx.a) 原材料(*.o)
  • 3. 发布静态库
# 发布静态库
	1. 提供头文件 **.h
	2. 提供制作出来的静态库 libxxx.a

1.2. 静态库制作举例

1.2.1 准备测试程序

  • 在某个目录中有如下的源文件,用来实现一个简单的计算器:
# 目录结构 add.c div.c mult.c sub.c -> 算法的源文件, 函数声明在头文件 head.h
# main.c中是对接口的测试程序, 制作库的时候不需要将 main.c 算进去
.
├── add.c
├── div.c
├── include
│   └── head.h
├── main.c
├── mult.c
└── sub.c
  • 加法计算源文件 add.c:
#include <stdio.h>
#include "head.h"

int add(int a, int b)
{
    return a+b;
}
  • 减法计算源文件 sub.c:
#include <stdio.h>
#include "head.h"

int subtract(int a, int b)
{
    return a-b;
}
  • 乘法计算源文件 mult.c:
#include <stdio.h>
#include "head.h"

int multiply(int a, int b)
{
    return a*b;
}
  • 除法计算源文件 div.c:
#include <stdio.h>
#include "head.h"

double divide(int a, int b)
{
    return (double)a/b;
}
  • 头文件 head.h:
  • 在C头文件中写上#ifndef(或者简写为ifdef)的作用是为了防止头文件的重复包含。当一个C源文件(或者另一个头文件)包含了该头文件时,预处理器会先检查头文件中是否已经定义了指定的标识符。如果已经定义了,则表示该头文件已经被包含过了,预处理器会跳过对该头文件的再次包含。
#ifndef _HEAD_H
#define _HEAD_H
// 加法
int add(int a, int b);
// 减法
int subtract(int a, int b);
// 乘法
int multiply(int a, int b);
// 除法
double divide(int a, int b);
#endif
  • 测试文件 main.c
#include <stdio.h>
#include "head.h"

int main()
{
    int a = 20;
    int b = 12;
    printf("a = %d, b = %d\n", a, b);
    printf("a + b = %d\n", add(a, b));
    printf("a - b = %d\n", subtract(a, b));
    printf("a * b = %d\n", multiply(a, b));
    printf("a / b = %f\n", divide(a, b));
    return 0;
}

1.2.2 生成静态库

  • 第一步:将源文件 add.c, div.c, mult.c, sub.c 进行汇编,得到二进制目标文件 add.o, div.o, mult.o, sub.o
# 1. 生成.o
gcc add.c div.c mult.c sub.c -c
sub.c:2:18: fatal error: head.h: No such file or directory
compilation terminated.

# 提示头文件找不到, 添加参数 -I 重新头文件路径即可
gcc add.c div.c mult.c sub.c -c -I ./include/

# 查看目标文件是否已经生成
tree
.
├── add.c
├── add.o            # 目标文件
├── div.c
├── div.o            # 目标文件
├── include
│   └── head.h
├── main.c
├── mult.c
├── mult.o           # 目标文件
├── sub.c
└── sub.o            # 目标文件
  • 第二步:将生成的目标文件通过 ar 工具打包生成静态库
# 2. 将生成的目标文件 .o 打包成静态库
$ ar rcs libcalc.a a.o b.o c.o    # a.o b.o c.o在同一个目录中可以写成 *.o

# 查看目录中的文件
$ tree
.
├── add.c
├── add.o
├── div.c
├── div.o
├── include
│   └── `head.h  ===> 和静态库一并发布
├── `libcalc.a   ===> 生成的静态库
├── main.c
├── mult.c
├── mult.o
├── sub.c
└── sub.o
  • 第三步:将生成的的静态库 libcalc.a 和库对应的头文件 head.h 一并发布给使用者就可以了。
# 3. 发布静态库
	1. head.h    => 函数声明
	2. libcalc.a => 函数定义(二进制格式)

1.3. 静态库的使用

  • 当我们得到了一个可用的静态库之后,需要将其放到一个目录中,然后根据得到的头文件编写测试代码,对静态库中的函数进行调用。
# 1. 首先拿到了发布的静态库
	`head.h` 和 `libcalc.a`
	
# 2. 将静态库, 头文件, 测试程序放到一个目录中准备进行测试
.
├── head.h          # 函数声明
├── libcalc.a       # 函数定义(二进制格式)
└── main.c          # 函数测试
  • 编译测试程序,得到可执行文件。
# 3. 编译测试程序 main.c
gcc main.c -o app
/tmp/ccR7Fk49.o: In function `main':
main.c:(.text+0x38): undefined reference to `add'
main.c:(.text+0x58): undefined reference to `subtract'
main.c:(.text+0x78): undefined reference to `multiply'
main.c:(.text+0x98): undefined reference to `divide'
collect2: error: ld returned 1 exit status

在这里插入图片描述

# 4. 编译的时候指定库信息
	-L: 指定库所在的目录(相对或者绝对路径)
	-l: 指定库的名字, 掐头(lib)去尾(.a) ==> calc
# -L -l, 参数和参数值之间可以有空格, 也可以没有  -L./ -lcalc
gcc main.c -o app -L ./ -l calc

# 查看目录信息, 发现可执行程序已经生成了
tree
.
├── app   		# 生成的可执行程序
├── head.h
├── libcalc.a
└── main.c

三. 动态库

  • 动态链接库是程序运行时加载的库,当动态链接库正确部署之后,运行的多个程序可以使用同一个加载到内存中的动态库,因此在 Linux 中 动态链接库也可称之为共享库

3.1. 为什么需要动态库

为什么需要动态库,其实也是静态库的特点导致。

  • ①. 空间浪费是静态库的一个问题。
  • ②. 另一个问题是静态库对程序的更新、部署和发布页会带来麻烦如果静态库liba.a更新了,所以使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,可能是一个很小的改动,却导致整个程序重新下载,全量更新)

在这里插入图片描述

  • 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2. 生成动态链接库

生成动态链接库是直接使用 gcc 命令并且需要添加 -fPIC(-fpic)以及-shared 参数。 -fpic是一个选项,用于生成位置独立的代码(Position Independent Code,PIC)

  • -fPIC或-fpic 参数的作用是使得 gcc 生成的代码是与位置无关的,也就是使用相对位置。
  • -shared参数的作用是告诉编译器生成一个动态链接库

在这里插入图片描述

在这里插入图片描述

生成动态链接库的具体步骤如下:

  • ①将源文件进行汇编操作,需要使用参数-c, 还需要添加额外参数-fpic /-fPIC
# 得到若干个 .o文件
gcc 源文件(*.c) -c -fpic
  • ②将得到的 .o 文件打包成动态库,还是使用 gcc, 使用参数-shared指定生成动态库 (位置没有要求)
gcc -shared 与位置无关的目标文件(*.o) -o 动态库(libxxx.so)
  • ③发布动态库和头文件
# 发布
 	1. 提供头文件: xxx.h
 	2. 提供动态库: libxxx.so

3.3. 动态库制作举例

  • 在此还是以上面制作静态库使用的实例代码为例来制作动态库,代码目录如下:
# 举例, 示例目录如下:
# 目录结构 add.c div.c mult.c sub.c -> 算法的源文件, 函数声明在头文件 head.h
# main.c中是对接口的测试程序, 制作库的时候不需要将 main.c 算进去
.
├── add.c
├── div.c
├── include
│   └── head.h
├── main.c
├── mult.c
└── sub.c
  • 第一步:使用 gcc 将源文件进行汇编 (参数-c), 生成与位置无关的目标文件,需要使用参数 -fpic或者-fPIC
# 1. 将.c汇编得到.o, 需要额外的参数 -fpic/-fPIC
$ gcc add.c div.c mult.c sub.c -c -fpic -I ./include/

# 查看目录文件信息, 检查是否生成了目标文件
$ tree
.
├── add.c
├── add.o                # 生成的目标文件
├── div.c
├── div.o                # 生成的目标文件
├── include
│   └── head.h
├── main.c
├── mult.c
├── mult.o               # 生成的目标文件
├── sub.c
└── sub.o                # 生成的目标文件
  • 第二步:使用 gcc 将得到的目标文件打包生成动态库,需要使用参数 -shared
# 2. 将得到 .o 打包成动态库, 使用gcc , 参数 -shared
$ gcc -shared add.o div.o mult.o sub.o -o libcalc.so  

# 检查目录中是否生成了动态库
$ tree
.
├── add.c
├── add.o
├── div.c
├── div.o
├── include
│   └── `head.h   ===> 和动态库一起发布
├── `libcalc.so   ===> 生成的动态库
├── main.c
├── mult.c
├── mult.o
├── sub.c
└── sub.o
  • 其实上面两个步骤可以合并为一个命令:gcc -fPIC -shared -o libcalc.so -c add.c div.c mult.c sub.c -I ./include/
  • 第三步:发布生成的动态库和相关的头文件
# 3. 发布库文件和头文件
	1. head.h
	2. libcalc.so

3.4. 动态库的使用

当我们得到了一个可用的动态库之后,需要将其放到一个目录中,然后根据得到的头文件编写测试代码,对动态库中的函数进行调用。

# 1. 拿到发布的动态库
	`head.h   libcalc.so
# 2. 基于头文件编写测试程序, 测试动态库中提供的接口是否可用
	`main.c`
# 示例目录:
.
├── head.h          ==> 函数声明
├── libcalc.so      ==> 函数定义
└── main.c          ==> 函数测试

编译测试程序

# 3. 编译测试程序
gcc main.c -o app
/tmp/ccwlUpVy.o: In function `main':
main.c:(.text+0x38): undefined reference to `add'
main.c:(.text+0x58): undefined reference to `subtract'
main.c:(.text+0x78): undefined reference to `multiply'
main.c:(.text+0x98): undefined reference to `divide'
collect2: error: ld returned 1 exit status

在这里插入图片描述

添加库信息相关参数,重新编译测试代码:

# 在编译的时候指定动态库相关的信息: 库的路径 -L, 库的名字 -l
gcc main.c -o app -L./ -lcalc

# 查看是否生成了可执行程序
tree
.
├── app 			# 生成的可执行程序
├── head.h
├── libcalc.so
└── main.c

# 执行生成的可执行程序, 错误提示 ==> 可执行程序执行的时候找不到动态库
$ ./app 
./app: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory

在这里插入图片描述

3.4. 解决动态库无法加载问题

3.4.1. 库的工作原理

在这里插入图片描述

3.4.2. 动态链接器

在这里插入图片描述

3.4.3. 解决方案

  • 可执行程序生成之后,根据动态链接器的搜索路径,我们可以提供三种解决方案,我们只需要将动态库的路径放到对应的环境变量或者系统配置文件中,同样也可以将动态库拷贝到系统库目录(或者是将动态库的软链接文件放到这些系统库目录中)。

在这里插入图片描述

3.4.4. 验证

在这里插入图片描述

补充:GCC学习

  • GCC:https://subingwen.cn/linux/gcc/?highlight=gcc
  • GNU 是一个递归缩写,表示 “GNU’s Not Unix!”(GNU 不是 Unix),它是一个广泛的自由软件项目,由 Richard Stallman 在 1983 年发起,目的是创建一个类似 Unix 的完全自由的操作系统。自由软件是指用户有运行,复制,分发,研究,修改和改进软件的自由的软件。
  • GNU 项目包含了大量的软件,包括软件许可证(如 GNU 通用公共许可证,简称 GPL),操作系统工具和组件(如 shell 工具,核心工具等),编程库,编译器(如 GCC),以及其他各种工具和应用程序
  • GCC 是 Linux 下的编译工具集,是 GNU Compiler Collection 的缩写,包含 gcc、g++ 等编译器。这个工具集不仅包含编译器,还包含其他工具集,例如 ar、nm 等。

1.1 gcc 工作流程|常用命令|多文件编译|gcc和g++

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • gcc常用命令
  • -fPIC:表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码, 念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。
  • -shared:指定生成动态链接库。
  • -static:指定生成静态链接库。
  • -L:表示要连接的静态或冬天库所在的目录
  • -l:指定链接时需要的动态库。编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.a/.so来确定库的名称。
  • -ggdb:此选项将尽可能的生成gdb 的可以使用的调试信息。
  • -Wl,options :把参数(options)传递给链接器ld 。如果options 中间有逗号,就将options分成多个选项,然后传递给链接程序。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 多文件编译

在这里插入图片描述
在这里插入图片描述

  • gcc和g++

在这里插入图片描述

补充:Makefile学习

  • https://subingwen.cn/linux/makefile/

在这里插入图片描述

1.1 规则|工作原理|变量|模式匹配|函数

在这里插入图片描述

补充:CMake学习

  • CMake 保姆级教程(上)https://subingwen.cn/cmake/CMake-primer/
  • CMake 保姆级教程(下):https://subingwen.cn/cmake/CMake-advanced/

1.1 CMake 概述|CMake的使用|预定义宏|嵌套的CMake|流程控制

在这里插入图片描述

参考文献

以上内容主要来自大神“爱编程的大丙”

  • C++静态库与动态库:https://www.cnblogs.com/skynet/p/3372855.html
  • Linux 静态库和动态库:https://subingwen.cn/linux/library/

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

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

相关文章

【JUC并发编程】Callable接口创建线程

一、介绍 与继承Thread类和实现Runnable接口两种创建线程方式的区别 ① Callable接口可以有返回值 ② Callable接口可以抛出异常 ③ 执行方法不同&#xff0c;call()方法和run()方法 二、代码演示 继承Thread类和实现Runnable接口的方式创建线程 package callable;import java…

celery Periodic Tasks 周期任务

celery Periodic Tasks 周期任务 https://docs.celeryq.dev/en/latest/userguide/periodic-tasks.html /home/mike/work/celery-5.3.1/examples/periodic-tasks myapp.py """myapp.pyUsage::# The worker service reacts to messages by executing tasks.(w…

pip安装指定包,找不到如何解决?

背景&#xff1a;现如今&#xff0c;在跑神经网络的时候&#xff0c;需要配置一些开源项目从而需要指定一些特定环境是必不可少的一个步骤&#xff0c;但是很多时候使用pip安装包的时候&#xff0c;总是找不到需要的版本。比如&#xff0c;今天需要配置open3d 0.15.1版本的环境…

群晖 nas 升级内存 手记(DS423+)

题外话&#xff1a; 我原来用的是群晖DS218&#xff0c;也用了5年了&#xff0c;今年5月份突然不能开机了&#xff0c;感觉故障不大&#xff0c;群晖官方又不好联系&#xff0c;非常麻烦。只好邮递到北京一家所谓的维修群晖的维修点&#xff0c;他们说维修费最多不超过200元&am…

Visual studio 快捷键(个人记录加深印象)

1、CtrlK 后 Ctrlx 插入代码片段快捷键&#xff08;或 编辑”>“IntelliSense”>“插入代码片段&#xff09; 注&#xff08;摘抄&#xff09;&#xff1a;该列表包含用于创建类、构造函数、for 循环、if 或 switch 语句等的代码片段

java定义数组的三种类型总结

三种定义数组的格式如下&#xff1a; int[] arr1new int[10]; int[] arr2{1,2,3,6}; int[] arr3new int[]{1,2,3,4,5,6,7,22}; 注意&#xff1a;数组的length是一个属性&#xff0c;而字符串的length()是一个方法了&#xff01;&#xff01;&#xff01;虽然都是求的他们各…

自定义 MVC 框架思想

目录 一、MVC设计模式 1. 什么是MVC 2. 三层架构与MVC的区别 二、自定义MVC框架 1. 为什么要学习自定义MVC框架 2. 自定义MVC的工作原理 3. 自定义MVC框架的优势 三、自定义MVC实例流程 1. mvc三层架构的弊端 2. 自定义MVC的工作流程 2.1 子控制器&#xff08;…

【flutter滑动拼图验证码】

Java后台使用aj_captcha插件&#xff0c;提供/captcha/get&#xff08;获取captcha底图和拼块图片&#xff09;、/captcha/check&#xff08;验证拼图偏移量&#xff09;这两个接口。并且这个插件在GitHub上有源码。 1.先准备好aj_captcha的工具类&#xff1a; import dart:co…

Linux指令与权限

本期我们来学习Linux的权限内容 目录 Linux权限 1.认识Linux下用户的分类 2.什么是权限 3.没有权限是什么现象 4.权限的修改问题 chmod chown chgrp umask 粘滞位 file指令 我们在使用xshell登录后&#xff0c;会有下面的东西 我们来介绍一下&#xff0c;以我的登录…

19. WebGPU —计算着色器(compute shader)

WebGPU 是即将推出的 Web API&#xff0c;可提供对GPU的底层控制并用于通用目的计算任务 。 我对计算机图形不是很有经验。我通过阅读有关如何使用 OpenGL 构建游戏引擎的教程了解了 WebGL 的点点滴滴&#xff0c;并通过观看 Inigo Quilez 在 ShaderToy 上仅使用着色器而不使用…

最长连续序列

题目链接 最长连续序列 题目描述 注意点 0 < nums.length < 100000不要求序列元素在原数组中连续 解答思路 要想实现时间复杂度为 O(n) 的算法解决此问题&#xff0c;关键是数字不能多次遍历&#xff0c;所以首先要对数组进行去重&#xff1b;然后为什么防止某个元素…

NSS [HNCTF 2022 WEEK2]ez_ssrf

NSS [HNCTF 2022 WEEK2]ez_ssrf 先拿dirsearch扫一下。 访问/flag.php 访问/index.php 应该是从index.php传参,ssrf然后访问到flag.php。 因此构造poc.php: <?php $out "GET /flag.php HTTP/1.1\r\n"; $out . "Host: 127.0.0.1\r\n"; $out . "…

网络关键设备和网络安全专用产品目录-2023年7月

2023年7月3日&#xff0c;网络关键设备和网络安全专用产品目录&#xff08;一级&#xff09;终于更新了&#xff0c;增加到38类&#xff0c;大家想了解每类产品对应哪家检测机构、以及涉及相关的标准、分解的二级产品目录&#xff0c;可以联系龙域认证客服。 一、网络关键设备…

01_面向对象的设计原则

面向对象的设计原则 参考资料&#xff1a; 视频书籍 《设计模式&#xff1a;可复用面向对象软件的基础》 简介 面对复杂问题如何解决&#xff1f; 分解&#xff1a;分而治之&#xff0c;大问题分解成小问题。抽象&#xff1a;忽视非本质的细节&#xff0c;处理泛化和理想化…

交换排序--冒泡排序和快速排序

交换&#xff0c;是指根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置 一&#xff0c;冒泡排序 1.基本思想&#xff1a;从后往前&#xff08;或从前往后&#xff09;两两比较相邻元素的值&#xff0c;若为逆序&#xff08;A[i-1] > A[i]&#xff09;&a…

Vivado创建IP核步骤

0、创建一个LED IP核 1、打开Vivado&#xff0c;点击Tasks栏的Manage IP&#xff0c;在弹出的选项框中选中New IP Location... 2、在弹出的界面选择Next 3、在弹出的界面中进行IP核的属性配置&#xff0c;修改系所属的器件和保存路径&#xff0c;其他的保持默认就行&#xff0…

Java(117):读取properties配置文件中文乱码问题解决

1、Edit展示properties后缀文件时乱码 2、读取properties配置文件中文乱码问题解决 2.1、文件存储为UTF-8格式 2.2、读取时设置为UTF-8格式 String enconding "UTF-8"; BufferedReader br new BufferedReader(new InputStreamReader(new FileInputStream(fileP…

VMware安装win10系统(超详细)

目录 一、创建虚拟机 二、选择自定义安装 三、根据自己的主机选择虚拟机的配置 四、光盘映像可以选择稍后安装​编辑 五、 根据自己的光盘映像选择操作系统和版本&#xff0c;因为我的装的是win10 x64&#xff0c;所以安装如下图所示 六、选择存放路径 七、 选择BIOS&#x…

java阻塞队列/kafka/spring整合kafka

queue增加删除元素 增加元素 add方法在添加元素的时候&#xff0c;若超出了度列的长度会直接抛出异常&#xff1a;put方法&#xff0c;若向队尾添加元素的时候发现队列已经满了会发生阻塞一直等待空间&#xff0c;以加入元素offer方法在添加元素时&#xff0c;如果发现队列已满…

FPGA实验三:状态机的设计

目录 一、实验目的 二、实验要求 三、实验代码 1.design source文件部分代码 2.测试文件代码 四、实验结果及分析 1、引脚锁定 2、仿真波形及分析 &#xff08;1&#xff09;设计好序列检测器 &#xff08;2&#xff09;仿真波形&#xff08;检测11010&#xff09; 3…