转载请注明出处。https://rhirufxmbcyj.gitlab.io
不定期更新~~~
如何用一套代码去处理32位、64位的文件结构解析
最近想写一个ELF文件格式解析程序,遇到了这样的一个问题
相信写过ELF或PE解析工具的朋友都会遇到过,就是两者的文件结构都有32位和64位区分
而这个差别也不,无非是结构体不同(某些字段是4字节或8字节)
因为这个微小的差异去写两套处理代码就显得程序过于臃肿,无法将代码合理的复用
不写两套代码的话,又无法动态的选择对应的32位或64位结构体
解决方案
这个方法是从同事那里学来的,巧妙的利用了#include
#include通俗的来说就是将被包含的文件在当前位置展开
例如
a.c里代码是这样写的
xxxxxxx
xxxxxxx
#include "b.c"
xxxxxxx
xxxxxxx
中间include了一个b.c,这个b.c的文件在编译过程中其实是相当于全部粘贴到a.c里来的,如果b.c不在工程中,那它根本不会参与编译,参与编译的其实只有a.c文件。
言归正传,用一套代码处理32 和 64两种情况就是利用上边这个方法
demo文件如下:
handle.c 存放处理代码,这个demo中只写了一接口函数的实现
handle.h 存放接口函数的定义,以及根据宏的不同定义不同的宏或变量等
main.c 调用接口函数
a.c 定义宏,然后include handle.c
b.c 定义宏,然后include handle.c
如果使用Cmake管理工程的话,记得不要将handle.c加入编译列表中
如果是用VS直接创建的工程,直接将handle.c从VS工程文件中移除,但是在文件夹中要保留
现在来看各个文件的内容
handle.c
#include <stdio.h>
#include "handle.h"
void CAT(function)()
{
printf(CAT(name));
printf("\n");
}
这里的CAT是一个宏,起到连接字符串的作用
handle.h
#ifndef HANDLE_H
#define HANDLE_H
void aaa_function();
void bbb_function();
#ifdef AAA
#define CAT(_X_) aaa_##_X_
char *aaa_name = "aaaaa";
#endif
#ifdef BBB
#define CAT(_X_) bbb_##_X_
char *bbb_name = "bbbbb";
#endif
#endif
a.c
#define AAA
#include "handle.c"
b.c
#define BBB
#include "handle.c"
main.c
#include "handle.h"
int main()
{
aaa_function();
bbb_function();
return 0;
}
照着这个demo去编译运行一下,发现确实是能跑通并输出相应的内容的。
可能直接理解起来有些难,最直观的方法还是手动展开来看比较方便。
咱们就从a.c 和 b.c入手进行展开
展开后的a.c
#define AAA //此处定义了AAA
//#include "handle.c"
#include <stdio.h>
//#include "handle.h"
void aaa_function();
void bbb_function();
#ifdef AAA //此处代码变成了可用的
#define CAT(_X_) aaa_##_X_
char *aaa_name = "aaaaa";
#endif
#ifdef BBB
#define CAT(_X_) bbb_##_X_
char *bbb_name = "bbbbb";
#endif
void CAT(function)() //这里实现了aaa_function的定义
{
printf(CAT(name));
printf("\n");
}
展开后的b.c
#define BBB //此处定义了BBB
//#include "handle.c"
#include <stdio.h>
//#include "handle.h"
void aaa_function();
void bbb_function();
#ifdef AAA
#define CAT(_X_) aaa_##_X_
char *aaa_name = "aaaaa";
#endif
#ifdef BBB //此处代码变成了可用的
#define CAT(_X_) bbb_##_X_
char *bbb_name = "bbbbb";
#endif
void CAT(function)() //这里实现了bbb_function的定义
{
printf(CAT(name));
printf("\n");
}
这样来看,也就一目了然了
程序员写了一套代码handle.c,经过两个文件的include,以及define宏定义和相应的处理变成了两套
编译运行自然没问题,代码也就不用多写一套相似的了
demo:https://rhirufxmbcyj.gitlab.io/files/handle_demo.zip
根据这个思路,可以定义PE32、PE64,或是ELF32、ELF64,然后用ifdef xxx来做相应的处理
用typedef对32位、64位结构体进一步封装使用
也就可以实现一套代码处理两套文件结构了
此方法应该也可用于其他需要多写一套代码处理的情况,请各位根据具体情况具体分析吧