在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系统上都可以实现。

相关文章
|
4月前
|
存储 编译器 程序员
c语言的文件操作与文件缓冲区
如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运行程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们可以使用文件。磁盘(硬盘)上的文件是文件。但是在程序设计中,我们⼀般谈的⽂件有两种:程序文件、数据文件(从文件功能的角度来分类 的)。就比如说我们电脑中以.txt为后缀的就是文件的一种,他就是数据文件。.exe为后缀的就为程序文件。函数名功能适用范围fgetc字符输入函数所有输入流fputc字符输出函数所有输出流fgets。
111 0
|
8月前
|
人工智能 C语言
|
9月前
|
存储 小程序 C语言
【C语言程序设计——文件】文件操作(头歌实践教学平台习题)【合集】
本文介绍了C语言中的文件操作,分为两个关卡。第1关任务是将键盘输入的字符(以#结束)存入`file1.txt`并显示输出;第2关任务是从键盘输入若干行文本(每行不超过80个字符,用-1作为结束标志),写入`file2.txt`后再读取并显示。文中详细讲解了文件的打开、读取(使用`fgetc()`和`fgets()`)、写入(使用`fputc()`和`fputs()`)及关闭操作,并提供了示例代码和测试说明。
246 5
|
11月前
|
大数据 C语言
C 语言动态内存分配 —— 灵活掌控内存资源
C语言动态内存分配使程序在运行时灵活管理内存资源,通过malloc、calloc、realloc和free等函数实现内存的申请与释放,提高内存使用效率,适应不同应用场景需求。
|
11月前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
634 3
|
10月前
|
存储 自然语言处理 Unix
【C语言】C语言 4 个编译过程详解
编译是将源代码转换为目标代码的过程。它是在编译器的帮助下完成的。编译器检查源代码是否存在语法或结构错误,如果源代码没有错误,则生成目标代码。
413 1
|
存储 自然语言处理 编译器
C语言编译和链接
C语言编译和链接
78 1
C语言编译和链接
|
12月前
|
存储 编译器 C语言
如何在 C 语言中判断文件缓冲区是否需要刷新?
在C语言中,可以通过检查文件流的内部状态或使用`fflush`函数尝试刷新缓冲区来判断文件缓冲区是否需要刷新。通常,当缓冲区满、遇到换行符或显式调用`fflush`时,缓冲区会自动刷新。
|
12月前
|
存储 编译器 C语言
C语言:文件缓冲区刷新方式有几种
C语言中文件缓冲区的刷新方式主要包括三种:自动刷新(如遇到换行符或缓冲区满)、显式调用 fflush() 函数强制刷新、以及关闭文件时自动刷新。这些方法确保数据及时写入文件。
|
10月前
|
算法 编译器 C语言
【C语言】C++ 和 C 的优缺点是什么?
C 和 C++ 是两种强大的编程语言,各有其优缺点。C 语言以其高效性、底层控制和简洁性广泛应用于系统编程和嵌入式系统。C++ 在 C 语言的基础上引入了面向对象编程、模板编程和丰富的标准库,使其适合开发大型、复杂的软件系统。 在选择使用 C 还是 C++ 时,开发者需要根据项目的需求、语言的特性以及团队的技术栈来做出决策。无论是 C 语言还是 C++,了解其优缺点和适用场景能够帮助开发者在实际开发中做出更明智的选择,从而更好地应对挑战,实现项目目标。
379 0