在C语言/C++中把资源编译进exe可执行文件,并运行时释放资源

简介: 在C语言/C++中把资源编译进exe可执行文件,并运行时释放资源

有时为了方便起见,我们会把资源文件(图片、声音等等)编译进exe程序,需要的时候释放出来。使用gcc可以实现这个东西。

1、安装TDM-GCC

TDM-GCC是推荐用的很好的编译器,基于mingw64改造,安装时会自动配置环境变量,简单方便。下载地址备用地址

2、准备资源文件并链接

通过objcopy命令链接资源文件为o文件:

# Windows系统下(编译64位程序时)objcopy -I binary -O pe-x86-64 -B i386:x86-64 资源文件名 输出的链接文件名
# Linux系统下(编译32位程序时)objcopy -I binary -O elf32-i386 -B i386 资源文件名 输出的链接文件名
# Linux系统下(编译64位程序时)objcopy -I binary -O elf64-x86-64 -B i386:x86-64 资源文件名 输出的链接文件名

注意输出的文件扩展名要是o。

比如我这里有一个jst.jar的文件,通过objcopy链接为jst.o

objcopy -I binary -O pe-x86-64 -B i386:x86-64 jst.jar jst.o

这样,当前目录下面出现了链接的文件:

网络异常,图片无法展示
|

再通过nm命令查询被链接的文件指针名:

nm 被链接的文件

例如我这里:

网络异常,图片无法展示
|

  • _binary_jst_jar_end 文件末指针
  • _binary_jst_jar_size 文件大小指针
  • _binary_jst_jar_start 文件头指针

3、编写C/C++源文件并合并编译

刚刚我们获取了文件各指针名,那么在C语言/C++中我们就可以使用它们了!具体先要用extern语句来声明它们为char数组类型,平时就用文件头指针和文件末指针即可。要获取文件大小,不建议直接用上面获得的大小指针,建议通过末指针减头指针来计算得到。我的代码如下:

#include <stdio.h>#include <stdlib.h>externchar_binary_jst_jar_start[]; //引用文件头指针externchar_binary_jst_jar_end[]; //引用文件末指针intmain() {
intsize=_binary_jst_jar_end-_binary_jst_jar_start; //始末指针相减得到文件大小printf("文件的起始指针为:%d\n", _binary_jst_jar_start);
printf("文件的结束指针为:%d\n", _binary_jst_jar_end);
printf("文件的大小:%d\n", size);
system("pause");
}

可以看到虽然引用的时候是char数组形式,但实质上它就是一个指针。数组名即为它的地址值。直接用其数组名获取地址。

C++的话操作方式相同,把printf换成cout语句即可。

然后再把资源文件和C源文件编译到一起:

C语言:

gcc C源文件 链接的资源文件 -o 编译输出文件

C++:

g++ C++源文件 链接的资源文件 -o 编译输出文件

例如我的:

// C:
gcc Main.c jst.o -o out.exe
// C++:
g++ Main.cpp jst.o -o out.exe

注意Windows上输出文件格式是exe的,linux可以不带格式(扩展名)。

在如果需要编译32位程序或者64位程序需要使用-m指定架构(不带m参数时跟随系统架构),例如下:

# C语言编译32位应用程序:gcc-m32 Main.c jst.o -o out.exe
# C语言编译64位应用程序:gcc-m64 Main.c jst.o -o out.exe
# C++编译32位应用程序:g++-m32 Main.cpp jst.o -o out.exe
# C++编译64位应用程序:g++-m64 Main.cpp jst.o -o out.exe

运行结果:

网络异常,图片无法展示
|

如果想释放这个文件怎么办呢?既然得到了文件始末指针,那么释放它也就很方便了。

在C语言中,先通过fopen建立一个新文件,释放文件时就写入到这个新文件里面(相当于这个新文件就是你释放的文件)。再用fwrite函数释放即可。例如我要把这个文件释放到E:\中转\outFile.jar,那么代码如下:

C语言:

#include <stdio.h>#include <stdlib.h>externchar_binary_jst_jar_start[]; //引用文件头指针externchar_binary_jst_jar_end[]; //引用文件末指针intmain() {
intsize=_binary_jst_jar_end-_binary_jst_jar_start; //始末指针相减得到文件大小FILE*fp=fopen("E:\\中转\\outFile.jar", "wb");  //创建文件指针,指定释放的位置并指定为二进制只写模式fwrite(_binary_jst_jar_start, size, 1, fp); //fwrite各参数含义:文件头指针位置,单次写入区块大小,写入区块数量,文件指针fclose(fp); //一定要fclose!否则文件可能损坏printf("文件释放完毕\n");
system("pause");
}

文件操作方面,C++和C语言略有不同。C++需要使用ofstream创建对象并打开文件,然后使用其write()函数写入。

C++:

#include <iostream>#include <fstream>#include <stdlib.h>usingnamespacestd;
externchar_binary_jst_jar_start[];
externchar_binary_jst_jar_end[];
intmain() {
intsize=_binary_jst_jar_end-_binary_jst_jar_start;
ofstreamfp;
fp.open("E:\\中转\\outFile.jar", ios::binary|ios::out);    //打开(指定)输出文件fp.write(_binary_jst_jar_start, size);    //write函数各参数意义:待写入数据头指针,写入的数据大小fp.close();
cout<<"文件释放完毕"<<endl;
system("pause");
}

结果:

网络异常,图片无法展示
|

它出现在了指定位置。

最后需要说明一下得是昨天通过测试,发现在Windows系统上只有64位的gcc/g++编译器才能实现这个。32位编译器或者编译32位程序这样做就无法编译通过。 Linux系统上都可以实现。

相关文章
|
15天前
|
Linux C语言
C语言获取文件长度
C语言获取文件长度
|
26天前
|
存储 编译器 C语言
【数据结构】C语言实现链队列(附完整运行代码)
【数据结构】C语言实现链队列(附完整运行代码)
36 0
|
26天前
|
存储 算法 程序员
【数据结构】C语言实现顺序表万字详解(附完整运行代码)
【数据结构】C语言实现顺序表万字详解(附完整运行代码)
39 0
|
28天前
|
存储 C++
基于C++的简易文件压缩与解压缩工具设计与实现
基于C++的简易文件压缩与解压缩工具设计与实现
15 3
|
30天前
|
API 数据库 C语言
【C/C++ 数据库 sqlite3】SQLite C语言API返回值深入解析
【C/C++ 数据库 sqlite3】SQLite C语言API返回值深入解析
169 0
|
30天前
|
安全 算法 程序员
【C/C++ 文件操作】深入理解C语言中的文件锁定机制
【C/C++ 文件操作】深入理解C语言中的文件锁定机制
33 0
|
23天前
|
人工智能 机器人 编译器
【C++】Windows端VS code中运行CMake工程(手把手教学)
【C++】Windows端VS code中运行CMake工程(手把手教学)
|
30天前
|
Linux 编译器 程序员
【Linux 调试秘籍】深入探索 C++:运行时获取堆栈信息和源代码行数的终极指南
【Linux 调试秘籍】深入探索 C++:运行时获取堆栈信息和源代码行数的终极指南
68 0
|
14天前
|
C语言 C++ 数据格式
【C++对于C语言的扩充】C++与C语言的联系,命名空间、C++中的输入输出以及缺省参数
【C++对于C语言的扩充】C++与C语言的联系,命名空间、C++中的输入输出以及缺省参数
|
18天前
|
开发框架 .NET 编译器
【C++】C++对C语言的关系,拓展及命名空间的使用
【C++】C++对C语言的关系,拓展及命名空间的使用