有时为了方便起见,我们会把资源文件(图片、声音等等)编译进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
数组类型,平时就用文件头指针和文件末指针即可。要获取文件大小,不建议直接用上面获得的大小指针,建议通过末指针减头指针来计算得到。我的代码如下:
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语言:
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++:
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系统上都可以实现。