当前位置: 首页 > 科技观察

C语言废话5:一个跨平台的头文件

时间:2023-03-14 12:37:01 科技观察

一、前言我们平时写代码的时候,尤其是制造轮子(给别人提供库文件)的时候,会遇到各种各样的需求场景:有些人需要在Linux下使用系统,有些人需要在windows系统下使用;有人用C语言开发,有人用C++开发;有人用动态库,有人用静态库;特别是在Windows系统中,库文件中导出的函数需要使用_declspec(dllexport)来声明函数,而用户在导入时需要使用_declspec(dllimport)来声明函数,非常麻烦!这篇短文分享了一个头文件,使用这个头文件,再加上编译时传递的几个宏,就可以完美的处理刚才提到的各种需求。2.先直接在头文件中添加代码,大家可以先尝试分析一下,后面我们会一一分析不同的使用场景。这个头文件的主要目的是定义一个宏:MY_API,然后在库文件中每个需要导出的函数或类的声明中加上这个宏。例如:voidMY_APIdo_work();这是头文件:_Pragma("once")#ifdefined(WIN32)||defined(_WIN32)||defined(__WIN32__)#defineMY_WIN32#elifdefined(linux)||defined(__linux)||defined(__linux__)#defineMY_LINUX#endif#ifdefined(MY_WIN32)#ifdefMY_API_STATIC#ifdef__cplusplus#defineMY_APIextern“C”#else#defineMY_API#endif#else#ifdefMY_API_EXPORTS#ifdef__cplusplus#defineMY_APIextern“C”__declspec(dllexport)#else#defineMY_API__declspec(dllexport)#ifdef__cplus#elseplus##defineMY_APIextern"C"__declspec(dllimport)#else#defineMY_API__declspec(dllimport)#endif#endif#endif#elifdefined(MY_LINUX)#ifdef__cplusplus#defineMY_APIextern"C"#else#defineMY_API#endif#endif定义的宏假设一个库文件需要写出来供别人使用。定义了上面的头文件后,其他文件必须包含这个头文件。1、平台宏定义不同的平台预先定义了相应的宏定义,例如:Windows平台:WIN32、_WIN32、WIN32;Linux平台:linux、__linux、linux;在某个平台上,这些宏可能没有全部定义,很可能只定义了其中一个宏。为了统一起见,我们在头文件的开头统一了这些可能的宏,定义了自己的平台宏定义:MY_WIN32或MY_LINUX。后面需要区分不同平台的时候,就用这个自定义的。平台宏。当然其他平台也可以继续扩展,比如:MY_MAC、MY_ARM等。2、编译器宏定义如果你在写库代码时使用C++,而用户使用C语言,那么你需要为库函数声明extern"C",这样编译器就不会修改函数名。改写。编译器g++预先定义了宏__cplusplus,所以在头文件中,这个宏就是用来给MY_API加上extern"C"语句的。四、Windows平台场景分析1、编译生成库文件(1)生成静态库在静态库中,不需要声明__declspec(dllexport/dllimport),所以只需要区分编译器(gcc或g++)即可。在编译选项中定义宏MY_API_STATIC,可以得到最终的MY_API为:gcc编译器:#defineMY_APIg++编译器:#defineMY_APIextern"C"(2)生成动态库在编译选项中,定义宏MY_API_EXPORTS,这样最终得到的MY_API就会变成:gcc编译器:#defineMY_API__declspec(dllexport)g++编译器:#defineMY_APIextern"C"__declspec(dllexport)include这个头文件,然后加入编译选项中定义的各种宏生成相应的MY_API宏定义。(1)使用静态库需要在编译选项中定义MY_API_STATIC,可以得到最终的MY_API如下:gcc编译器:#defineMY_APIg++编译器:#defineMY_APIextern"C"(2)使用动态librariesinthecompilationoptions最终的MY_API不需要任何宏定义即可得到:gcccompiler:#defineMY_APIextern"C"__declspec(dllimport)g++compiler:#defineMY_API__declspec(dllimport)这相当于声明了导入库函数。五、Linux平台场景分析Linux平台就简单多了,只需要注意编译器的问题,没有export和import的区分。