使用c++解压rar文件,基于UnRAR64,非命令行

news2024/9/30 1:25:56

最近项目需要解压缩rar文件,我们都知道rar是闭源收费软件,如果直接采用命令行可能会有限制,或者盗版问题,使用正版的winrar命令行解压rar文件是否有限制,这个我没来得及测试,但是从交互体验上来说,命令行对于很多情况的处理也不太友好,比如是否出错,比如异常处理,甚至某些高级功能,比如自定义解压缩的文件名等等,这些在命令行中不太好实现甚至无法实现。

网上很多关于c++解压rar的代码都是基于命令行的,这不是我想要的。

我想找能够解压rar的库或者dll,经过一番寻找,发现rarlab官网已经提供了UnRAR64,可以直接下载运行,这里提供一下下载地址:https://www.rarlab.com/rar/unrardll-624.exeicon-default.png?t=N7T8https://www.rarlab.com/rar/unrardll-624.exe

其他版本在这个页面:WinRAR archiver, a powerful tool to process RAR and ZIP filesicon-default.png?t=N7T8https://www.rarlab.com/rar_add.htm

使用官方的例子,即可实现winrar的解压缩,不过为了方便使用,我拓展了一下官方的代码,可以实现列出文件和解压缩rar文件到指定的目录,修改比较简单,这里直接上代码:

#pragma once


#include <windows.h>
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <vector>

#include "unrar.h"

enum { EXTRACT, TEST, PRINT, LIST };

int CommandLine(int Argc, char *Argv[]);

void ExtractArchive(char *ArcName,int Mode);
void ExtractArchive(char *ArcName, char* DstDir);
void ListArchive(char *ArcName);
size_t ListArchive(char *ArcName, std::vector<std::string>& vFiles);
void ShowComment(wchar_t *CmtBuf);
void OutHelp(void);

enum ERR_TYPE {ERR_OPEN, ERR_READ, ERR_PROCESS};
void OutError(int Error,char *ArcName,int ErrType);

void ShowArcInfo(unsigned int Flags,char *ArcName);
void PrintTime(const char *Label,unsigned int Low,unsigned int High);
void OutProcessFileError(int Error);
int CALLBACK CallbackProc(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2);

实现文件:

#define STRICT

#include "UnRDLL.h"

int CommandLine(int Argc, char *Argv[])
{
  setlocale(LC_ALL, NULL);

  if (Argc!=3)
  {
    OutHelp();
    return(0);
  }

  switch(toupper(Argv[1][0]))
  {
    case 'X':
      ExtractArchive(Argv[2],EXTRACT);
      break;
    case 'T':
      ExtractArchive(Argv[2],TEST);
      break;
    case 'P':
      ExtractArchive(Argv[2],PRINT);
      break;
    case 'L':
      ListArchive(Argv[2]);
      break;
    default:
      OutHelp();
      return(0);
  }

  return(0);
}


void ExtractArchive(char *ArcName,int Mode)
{
  HANDLE hArcData;
  int RHCode,PFCode;
  wchar_t CmtBuf[16384];
  struct RARHeaderData HeaderData;
  struct RAROpenArchiveDataEx OpenArchiveData;

  memset(&HeaderData,0,sizeof(HeaderData));
  memset(&OpenArchiveData,0,sizeof(OpenArchiveData));

  OpenArchiveData.ArcName=ArcName;
  OpenArchiveData.CmtBufW=CmtBuf;
  OpenArchiveData.CmtBufSize=sizeof(CmtBuf)/sizeof(CmtBuf[0]);
  OpenArchiveData.OpenMode=RAR_OM_EXTRACT;
  OpenArchiveData.Callback=CallbackProc;
  OpenArchiveData.UserData=Mode;
  hArcData=RAROpenArchiveEx(&OpenArchiveData);

  if (OpenArchiveData.OpenResult!=0)
  {
    OutError(OpenArchiveData.OpenResult,ArcName,ERR_OPEN);
    return;
  }

  ShowArcInfo(OpenArchiveData.Flags,ArcName);

  if (OpenArchiveData.CmtState==1)
    ShowComment(CmtBuf);

  while ((RHCode=RARReadHeader(hArcData,&HeaderData))==0)
  {
    switch(Mode)
    {
      case EXTRACT:
        printf("\nExtracting %-45s",HeaderData.FileName);
        break;
      case TEST:
        printf("\nTesting %-45s",HeaderData.FileName);
        break;
      case PRINT:
        printf("\nPrinting %-45s\n",HeaderData.FileName);
        break;
    }
    PFCode=RARProcessFile(hArcData,(Mode==EXTRACT) ? RAR_EXTRACT:RAR_TEST,
                          NULL,NULL);
    if (PFCode==0)
      printf(" OK");
    else
    {
      OutError(PFCode,ArcName,ERR_PROCESS);
      break;
    }
  }

  OutError(RHCode,ArcName,ERR_READ);

  RARCloseArchive(hArcData);
}


void ExtractArchive(char *ArcName, char* DstDir)
{
	HANDLE hArcData;
	int RHCode,PFCode;
	wchar_t CmtBuf[16384];
	struct RARHeaderData HeaderData;
	struct RAROpenArchiveDataEx OpenArchiveData;

	memset(&HeaderData,0,sizeof(HeaderData));
	memset(&OpenArchiveData,0,sizeof(OpenArchiveData));

	OpenArchiveData.ArcName=ArcName;
	OpenArchiveData.CmtBufW=CmtBuf;
	OpenArchiveData.CmtBufSize=sizeof(CmtBuf)/sizeof(CmtBuf[0]);
	OpenArchiveData.OpenMode=RAR_OM_EXTRACT;
	OpenArchiveData.Callback=CallbackProc;
	OpenArchiveData.UserData= EXTRACT;
	hArcData=RAROpenArchiveEx(&OpenArchiveData);

	if (OpenArchiveData.OpenResult!=0)
	{
		OutError(OpenArchiveData.OpenResult,ArcName,ERR_OPEN);
		return;
	}

	ShowArcInfo(OpenArchiveData.Flags,ArcName);

	if (OpenArchiveData.CmtState==1)
		ShowComment(CmtBuf);

	while ((RHCode=RARReadHeader(hArcData,&HeaderData))==0)
	{
		printf("\nExtracting %-45s",HeaderData.FileName);
		PFCode=RARProcessFile(hArcData,RAR_EXTRACT,DstDir,NULL);
		if (PFCode==0)
			printf(" OK");
		else
		{
			OutError(PFCode,ArcName,ERR_PROCESS);
			break;
		}
	}

	OutError(RHCode,ArcName,ERR_READ);

	RARCloseArchive(hArcData);
}

size_t ListArchive(char *ArcName, std::vector<std::string>& vFiles)
{
  HANDLE hArcData;
  int RHCode,PFCode;
  wchar_t CmtBuf[16384];
  struct RARHeaderDataEx HeaderData;
  struct RAROpenArchiveDataEx OpenArchiveData;
  wchar_t RedirName[1024];

  memset(&HeaderData,0,sizeof(HeaderData));
  memset(&OpenArchiveData,0,sizeof(OpenArchiveData));
  OpenArchiveData.ArcName=ArcName;
  OpenArchiveData.CmtBufW=CmtBuf;
  OpenArchiveData.CmtBufSize=sizeof(CmtBuf)/sizeof(CmtBuf[0]);
  OpenArchiveData.OpenMode=RAR_OM_LIST;
  OpenArchiveData.Callback=CallbackProc;
  OpenArchiveData.UserData=LIST;
  hArcData=RAROpenArchiveEx(&OpenArchiveData);

  if (OpenArchiveData.OpenResult!=0)
  {
    OutError(OpenArchiveData.OpenResult,ArcName,ERR_OPEN);
    return 0;
  }

  ShowArcInfo(OpenArchiveData.Flags,ArcName);

  if (OpenArchiveData.CmtState==1)
    ShowComment(CmtBuf);

  HeaderData.RedirName=RedirName;
  HeaderData.RedirNameSize=sizeof(RedirName)/sizeof(RedirName[0]);
  while ((RHCode=RARReadHeaderEx(hArcData,&HeaderData))==0)
  {
    __int64 UnpSize=HeaderData.UnpSize+(((__int64)HeaderData.UnpSizeHigh)<<32);
    __int64 PackSize=HeaderData.PackSize+(((__int64)HeaderData.PackSizeHigh)<<32);
    printf("\nName:   %s",HeaderData.FileName);

	vFiles.push_back(HeaderData.FileName);

    printf("\nSize:   %lld ",UnpSize);
    printf("\nPacked: %lld ",PackSize);

    PrintTime("mtime",HeaderData.MtimeLow,HeaderData.MtimeHigh);
    PrintTime("ctime",HeaderData.CtimeLow,HeaderData.CtimeHigh);
    PrintTime("atime",HeaderData.AtimeLow,HeaderData.AtimeHigh);

    if (HeaderData.RedirType!=0)
      printf("\n\tlink type %d, target %ls",HeaderData.RedirType,HeaderData.RedirName);
    if ((PFCode=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL))!=0)
    {
      OutError(PFCode,ArcName,ERR_PROCESS);
      break;
    }
    printf("\n");
  }

  OutError(RHCode,ArcName,ERR_READ);

  RARCloseArchive(hArcData);

  return vFiles.size();
}

void ListArchive(char *ArcName)
{
  HANDLE hArcData;
  int RHCode,PFCode;
  wchar_t CmtBuf[16384];
  struct RARHeaderDataEx HeaderData;
  struct RAROpenArchiveDataEx OpenArchiveData;
  wchar_t RedirName[1024];

  memset(&HeaderData,0,sizeof(HeaderData));
  memset(&OpenArchiveData,0,sizeof(OpenArchiveData));
  OpenArchiveData.ArcName=ArcName;
  OpenArchiveData.CmtBufW=CmtBuf;
  OpenArchiveData.CmtBufSize=sizeof(CmtBuf)/sizeof(CmtBuf[0]);
  OpenArchiveData.OpenMode=RAR_OM_LIST;
  OpenArchiveData.Callback=CallbackProc;
  OpenArchiveData.UserData=LIST;
  hArcData=RAROpenArchiveEx(&OpenArchiveData);

  if (OpenArchiveData.OpenResult!=0)
  {
    OutError(OpenArchiveData.OpenResult,ArcName,ERR_OPEN);
    return;
  }

  ShowArcInfo(OpenArchiveData.Flags,ArcName);

  if (OpenArchiveData.CmtState==1)
    ShowComment(CmtBuf);

  HeaderData.RedirName=RedirName;
  HeaderData.RedirNameSize=sizeof(RedirName)/sizeof(RedirName[0]);
  while ((RHCode=RARReadHeaderEx(hArcData,&HeaderData))==0)
  {
    __int64 UnpSize=HeaderData.UnpSize+(((__int64)HeaderData.UnpSizeHigh)<<32);
    __int64 PackSize=HeaderData.PackSize+(((__int64)HeaderData.PackSizeHigh)<<32);
    printf("\nName:   %s",HeaderData.FileName);
    printf("\nSize:   %lld ",UnpSize);
    printf("\nPacked: %lld ",PackSize);

    PrintTime("mtime",HeaderData.MtimeLow,HeaderData.MtimeHigh);
    PrintTime("ctime",HeaderData.CtimeLow,HeaderData.CtimeHigh);
    PrintTime("atime",HeaderData.AtimeLow,HeaderData.AtimeHigh);

    if (HeaderData.RedirType!=0)
      printf("\n\tlink type %d, target %ls",HeaderData.RedirType,HeaderData.RedirName);
    if ((PFCode=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL))!=0)
    {
      OutError(PFCode,ArcName,ERR_PROCESS);
      break;
    }
    printf("\n");
  }

  OutError(RHCode,ArcName,ERR_READ);

  RARCloseArchive(hArcData);
}


void ShowComment(wchar_t *CmtBuf)
{
  printf("\nComment:\n%ls\n",CmtBuf);
}


void OutHelp(void)
{
  printf("\nUNRDLL.   This is a simple example of UNRAR.DLL usage\n");
  printf("\nSyntax:\n");
  printf("\nUNRDLL X <Archive>     extract archive contents");
  printf("\nUNRDLL T <Archive>     test archive contents");
  printf("\nUNRDLL P <Archive>     print archive contents to stdout");
  printf("\nUNRDLL L <Archive>     view archive contents\n");
}


void OutError(int Error,char *ArcName,int ErrType)
{
  switch(Error)
  {
    case ERAR_NO_MEMORY:
      printf("\nNot enough memory");
      break;
    case ERAR_BAD_DATA:
      printf("\n%s: archive header or data are damaged",ArcName);
      break;
    case ERAR_BAD_ARCHIVE:
      printf("\n%s is not RAR archive",ArcName);
      break;
    case ERAR_UNKNOWN_FORMAT:
      printf("Unknown archive format");
      break;
    case ERAR_EOPEN:
      if (ErrType==ERR_PROCESS) // Returned by RARProcessFile.
        printf("Volume open error");
      else
        printf("\nCannot open %s",ArcName);
      break;
    case ERAR_ECREATE:
      printf("File create error");
      break;
    case ERAR_ECLOSE:
      printf("File close error");
      break;
    case ERAR_EREAD:
      printf("Read error");
      break;
    case ERAR_EWRITE:
      printf("Write error");
      break;
    case ERAR_SMALL_BUF:
      printf("Buffer for archive comment is too small, comment truncated");
      break;
    case ERAR_UNKNOWN:
      printf("Unknown error");
      break;
    case ERAR_MISSING_PASSWORD:
      printf("Password for encrypted file or header is not specified");
      break;
    case ERAR_EREFERENCE:
      printf("Cannot open file source for reference record");
      break;
    case ERAR_BAD_PASSWORD:
      printf("Wrong password is specified");
      break;
  }
}


void ShowArcInfo(unsigned int Flags,char *ArcName)
{
  printf("\nArchive %s\n",ArcName);
  printf("\nVolume:\t\t%s",(Flags & 1) ? "yes":"no");
  printf("\nComment:\t%s",(Flags & 2) ? "yes":"no");
  printf("\nLocked:\t\t%s",(Flags & 4) ? "yes":"no");
  printf("\nSolid:\t\t%s",(Flags & 8) ? "yes":"no");
  printf("\nNew naming:\t%s",(Flags & 16) ? "yes":"no");
  printf("\nRecovery:\t%s",(Flags & 64) ? "yes":"no");
  printf("\nEncr.headers:\t%s",(Flags & 128) ? "yes":"no");
  printf("\nFirst volume:\t%s",(Flags & 256) ? "yes":"no or older than 3.0");
  printf("\n---------------------------\n");
}


void PrintTime(const char *Label,unsigned int Low,unsigned int High)
{
  if (Low!=0 || High!=0)
  {
    FILETIME ft;
    ft.dwLowDateTime=Low;
    ft.dwHighDateTime=High;
    SYSTEMTIME ust,st;
    FileTimeToSystemTime(&ft,&ust);
    SystemTimeToTzSpecificLocalTime(NULL,&ust,&st);
    printf("\n%s:  %u-%02u-%02u %02u:%02u:%02u,%03u",Label,st.wYear,st.wMonth,
           st.wDay,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
  }
}


int CALLBACK CallbackProc(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2)
{
  switch(msg)
  {
    case UCM_CHANGEVOLUMEW:
      if (P2==RAR_VOL_ASK)
      {
        printf("\n\nVolume %S is required\nPossible options:\n",(wchar_t *)P1);
        printf("\nEnter - try again");
        printf("\n'R'   - specify a new volume name");
        printf("\n'Q'   - quit");
        printf("\nEnter your choice: ");
        switch(toupper(getchar()))
        {
          case 'Q':
            return(-1);
          case 'R':
            {
              wchar_t *eol;
              printf("\nEnter new name: ");
              fflush(stdin);

              // fgetws may fail to read non-English characters from stdin
              // in some compilers. In this case use something more
              // appropriate for Unicode input.
              fgetws((wchar_t *)P1,MAX_PATH,stdin);

              eol=wcspbrk((wchar_t *)P1,L"\r\n");
              if (eol!=NULL)
                *eol=0;
            }
            return(1);
          default:
            return(1);
        }
      }
      if (P2==RAR_VOL_NOTIFY)
        printf("\n  ... volume %S\n",(wchar_t *)P1);
      return(1);
    case UCM_PROCESSDATA:
      if (UserData==PRINT)
      {
        fflush(stdout);
        fwrite((char *)P1,1,P2,stdout);
        fflush(stdout);
      }
      return(1);
    case UCM_NEEDPASSWORDW:
      {
        wchar_t *eol;
        printf("\nPassword required: ");
   
        // fgetws may fail to read non-English characters from stdin
        // in some compilers. In this case use something more appropriate
        // for Unicode input.
        fgetws((wchar_t *)P1,(int)P2,stdin);

        eol=wcspbrk((wchar_t *)P1,L"\r\n");
        if (eol!=NULL)
          *eol=0;
      }
      return(1);
  }
  return(0);
}

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

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

相关文章

深兰科技科研团队6篇论文被国际医学信息科学顶尖学术会议收录

近日&#xff0c;深兰科技科学院智能科学首席科学家黄智生教授及其所带领的科研团队与同济大学团队&#xff0c;北京工业大学团队等合作&#xff0c;在国际医学信息科学顶尖学术会议“HIS 2023”上接连发表了六篇论文(其中有两篇论文的第一作者是黄教授本人)。 10月下旬&#x…

太坑了,降低 代码可读性的 12 个技巧

工作六七年以来&#xff0c;接手过无数个烂摊子&#xff0c;屎山雕花、开关编程已经成为常态。 下面细数一下 降低代码可读性&#xff0c;增加维护难度的 12 个编码“技巧”。 假设一个叫”二狗“ 的程序员&#xff0c;喜欢做以下事情。 1. 二狗积极拆分微服务&#xff0c;一个…

软文推广如何提高点击率,媒介盒子告诉你

随着软文推广的广泛应用&#xff0c;对于广告主来说&#xff0c;提高点击率已经成为一项关键任务&#xff0c;点击率直接影响广告主的投资回报率&#xff0c;今天媒介盒子将从两大方面给出软文推广如何提高点击率的建议&#xff1a; 一、 优化广告文案 广告文案是影响点击率的…

[动态规划] (十二) 简单多状态 LeetCode 213.打家劫舍II

[动态规划] (十二) 简单多状态: LeetCode 213.打家劫舍II 文章目录 [动态规划] (十二) 简单多状态: LeetCode 213.打家劫舍II题目解析解题思路状态表示状态转移方程初始化和填表顺序返回值提醒 代码实现总结 213. 打家劫舍 II 题目解析 本题是对打家劫舍和按摩师的升级题型&am…

ae如何保存为gif格式?三个方法轻松搞定!

GIF是动态图像&#xff0c;在聊天的时候发的动态表情包就是GIF&#xff0c;非常受大家欢迎。那么如何把视频变成GIF格式呢&#xff0c;下面是一些具体的操作步骤。 一、AE 1、依次点击AE菜单栏文件 — 导出 — 添加到渲染队列 — 导出MOV视频格式 2、依次点击导入MOV — 储存W…

jenkins原理篇——成员权限管理

大家好&#xff0c;我是蓝胖子&#xff0c;前面几节我讲述了jenkins的语法以及我是如何使用jenkins对测试和正式环境进行发布的。但正式环境使用jenkins还有一点很重要&#xff0c;那就是权限管理。正式环境的权限往往不能对所有人开放&#xff0c;以及要做到每次发布都是谁在操…

PMI-ACP(103:57- 103)

57/103 高绩效敏捷团队的特征 参与式指导有效的决策开放和清晰的沟通价值多样性相互信任管理冲突清楚目标明确定义角色 和 职责协调关系积极的氛围 58/103 创建授权团队 敏捷强调 具备授权和积极性 的自我管理团队&#xff0c;他们需要对项目成果充分负责&#xff0c;授权是…

0基础两小时建网站

​作者主页 &#x1f4da;lovewold少个r博客主页 ⚠️本文重点&#xff1a;0基础2小时搭建个人网站 &#x1f449;【C-C入门系列专栏】&#xff1a;博客文章专栏传送门 &#x1f604;每日一言&#xff1a;宁静是一片强大而治愈的神奇海洋&#xff01; 目录 前言 第一步 环境…

Redis Desktop Manager安装和使用

Redis Desktop Manager&#xff08;RDM&#xff09;是一款用于管理和操作Redis数据库的图形化界面工具。提供了简单易用的界面&#xff0c;使用户能够方便地执行各种Redis数据库操作&#xff0c;并且支持多个Redis服务器的连接RDM功能介绍&#xff1a;1.连接管理&#xff1a;RD…

DC-DC降压芯片120V转12V5A大功率SL3038电源芯片

本文将介绍一款DC-DC降压芯片&#xff0c;将120V的电压转换为12V5A的大功率输出&#xff0c;使用SL3038电源芯片实现。在开始介绍之前&#xff0c;我们先来了解一下DC-DC降压芯片和SL3038电源芯片的基本原理和特点。 DC-DC降压芯片是一种常见的电源管理芯片&#xff0c;它可以将…

爱上联名的白酒,还是拿不下年轻人?

作者&#xff5c;Kyra 编辑&#xff5c;Ray “才喝完“酱香拿铁”&#xff0c;又吃了“浓香冰淇淋&#xff0c;古茗和天官赐福的联名刚也已经下单了&#xff0c;完美。”热衷于收集各种联名的Bella在办公室欢呼道。 现在品牌之间的联名意欲拿捏年轻人&#xff0c;特别是白酒…

maven中的install 和 clean命令,以及compile、、package、test等操作介绍

maven中的install命令 主要就是谁要被其他模块依赖就install谁 Maven工具可以进行clean、compile、install、package、test等操作&#xff0c;但是这些操作有什么用呢&#xff0c;以下面的p2p-exterface为例说明一下&#xff0c;pwp-exterface工程目录如下&#xff1a; com…

从JDK8升级到JDK17

JDK8太老了&#xff0c;发布10年了吧&#xff0c;新开发的还是用最新免费长期支持版JDK17吧。这次把工程和环境升级到JDK17再继续后面工作&#xff0c;避免后面写多了还得解决升级问题。 先从官网下载JDK17 下载地址 解压后的文件夹放到一个位置 然后修改环境变量 修改好之…

IntelliJ IDEA 如何修改默认Maven仓库地址

在使用idea过程中&#xff0c;每次新建项目或者打开项目时&#xff0c;maven仓库地址都会变为默认地址。如何修改默认地址&#xff0c;让其保持不变&#xff0c;如下这种方式可以简单快捷的设置。 1.打开idea&#xff0c;取消项目自动加载 2.点击 Customize,然后再点击 All se…

spdk用户态块层详解

先通过回顾内核态的通用块层来详细介绍SPDK通用块层&#xff0c;包括通用块层的架构、核心数据结构、数据流方面的考量等。最后描述基于通用块层之上的两个特性&#xff1a;一是逻辑卷的支持&#xff0c;基于通用块设备的Blobstore和各种逻辑卷的特性&#xff0c;精简配置&…

【数据结构】树与二叉树(四):满二叉树、完全二叉树及其性质

文章目录 5.1 树的基本概念5.1.1 树的定义5.1.2 森林的定义5.1.3 树的术语5.1.4 树的表示 5.2 二叉树5.2.1 二叉树1. 定义2. 特点3. 性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉…

【git】TortoiseGit图标不显示 及 文件夹中.git文件夹不显示

&#xff08;一&#xff09;文件夹中.git文件夹不显示 在 文件夹选项-查看-高级设置 中&#xff0c; 将 隐藏文件和文件夹中的不显示&#xff0c;标记为“显示隐藏的文件、文件夹和驱动器” &#xff08;二&#xff09;TortoiseGit图标不显示 【情况一】是否有正确安装 Tort…

【STM32-DSP库的使用】基于Keil5 + STM32CubeMX 手动添加、库添加方式

STM32-DSP库的使用 一.CMSIS-DSP1.1 DSP库简介1.2 支持的函数类别1.3 宏定义 二、操作2.1 STM32CubeMX 配置基本工程2.2 Lib库的方式实现(推荐)2.3 手动添加DSP文件&#xff08;可以下载官方最新库&#xff0c;功能齐全&#xff09; 三、MFCC测试DSP加速效果 为验证语音识别MFC…