跨平台代码的3种组织方式

蓮花仙者
发布: 2025-09-07 08:08:01
原创
329人浏览过

一、起源

在前一篇文章中,我分享了一个跨平台头文件的示例,该示例在 Windows 平台上更为重要,因为它需要处理库函数的导入和导出声明(dllexport、dllimport)。基于这个头文件,我们可以进一步扩展,以实现更细粒度的控制,比如对编译器和其版本的判断。

在源代码中,我们同样会遇到一些跨平台的问题。不同平台上的相同功能,实现方式可能有所不同。那么,如何有效地组织这些平台相关的代码呢?本文将探讨这个问题。

PS:文末将提供一个简单的跨平台构建代码示例。

二、问题引入

假设我们要编写一个库,需要实现一个获取系统时间戳的函数。作为库的作者,你决定提供以下API函数:

我们的任务是在函数实现中,通过不同平台下的C库或系统调用来计算系统当前的时间戳。

在Linux平台下,可以通过以下代码实现:

struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
登录后复制

在Windows平台下,可以通过以下代码实现:

struct timeb tp;
ftime(&tp);
return tp.time * 1000 + tp.millitm;
登录后复制

那么问题来了:如何将这两段平台相关的代码组织在一起?下面将介绍三种不同的组织方式,这些方式没有优劣之分,适合每个人和团队的不同习惯。

此外,这个示例中只有一个函数,而且较短。如果有许多跨平台的函数,且都很长,你的选择可能会有所不同。

三、三个解决方案

方案1

直接在接口函数中,通过平台宏定义来区分不同平台。

平台宏定义(T_LINUX, T_WINDOWS)是在前一篇文章中介绍的,通过操作系统和编译器来判断当前平台,并定义统一的平台宏供我们使用:

代码组织方式如下:

int64 t_get_timestamp() {
    int64 ts = -1;
    #if defined(T_LINUX)
        struct timeval tv;
        gettimeofday(&tv, NULL);
        ts = tv.tv_sec * 1000 + tv.tv_usec / 1000;
    #elif defined(T_WINDOWS)
        struct timeb tp;
        ftime(&tp);
        ts = tp.time;
        ts = ts * 1000 + tp.millitm;
    #endif
    return ts;
}
登录后复制

这种方式将所有平台代码放在API函数中,通过平台宏定义进行条件编译。由于代码较短,看起来还不错。

方案2

将不同平台的实现代码放在独立的文件中,然后通过#include预处理符号,在API函数中引入平台相关的代码。

增加两个文件:

(1) t_time_linux.c

Wand AI
Wand AI

一个无代码AI平台,帮助组织快速创建基于AI的业务解决方案

Wand AI 81
查看详情 Wand AI
#include "t_time.h"
#include <sys/time.h>
<p>int64 t_get_timestamp() {
int64 ts = -1;
struct timeval tv;
gettimeofday(&tv, NULL);
ts = tv.tv_sec * 1000 + tv.tv_usec / 1000;
return ts;
}
登录后复制

(2) t_time_windows.c

#include "t_time.h"</p><h1>include <windows.h></h1><h1>include <sys/timeb.h></h1><p>int64 t_get_timestamp() {
int64 ts = -1;
struct timeb tp;
ftime(&tp);
ts = tp.time;
ts = ts * 1000 + tp.millitm;
return ts;
}
登录后复制

(3) t_time.c

这个文件不做任何事情,仅用于include其他代码。

#include "t_time.h"</p><h1>if defined(T_LINUX)</h1><pre class="brush:php;toolbar:false;"><pre class="brush:php;toolbar:false;">#include "t_time_linux.c"
登录后复制

elif defined(T_WINDOWS)

<pre class="brush:php;toolbar:false;">#include "t_time_windows.c"
登录后复制

else

<pre class="brush:php;toolbar:false;">int64 t_get_timestamp() {
    return -1;
}
登录后复制

endif

有些人可能不喜欢这种组织方式,因为通常我们会include头文件(.h),而这里通过平台宏定义include不同的源文件(.c),感觉有些怪异。

实际上,一些开源库也是这样做的,例如:

跨平台代码的3种组织方式

方案3

在方案2中,我们是在源代码中填入不同平台的实现代码。

实际上,我们可以换一种思路,既然已经根据平台的不同放在了不同的文件中,那么可以通过让不同的源文件加入到编译过程中来实现。

我们使用cmake工具来构建测试代码,因此可以编辑CMakelists.txt文件,来控制参与编译的源文件。

CMakelists.txt文件部分内容:

# 设置平台变量</h1><p>if (CMAKE_SYSTEM_NAME MATCHES "Linux")
set(PLATFORM linux)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
set(PLATFORM windows)
endif()</p><h1>根据平台变量,来编译不同的源文件</h1><p>set(LIBSRC  t<em>time</em>${PLATFORM}.c)
登录后复制

这种组织方式让代码看起来更“干净”。同样,我们也可以看到一些开源库也是这样做的:

跨平台代码的3种组织方式跨平台代码的3种组织方式

四、One More Thing

由于文章篇幅原因,上述仅展示了代码片段。

我编写了一个最简单的demo,使用cmake来构建跨平台的动态库、静态库和可执行程序。这个demo的主要目的是作为一个外壳,用于测试文章中的代码。

在Linux平台下,可以通过cmake指令手动编译;在Windows平台下,可以通过CLion集成开发环境直接编译和执行,也可以通过cmake工具直接生成VS2017/2019解决方案。

这个demo已上传至gitee仓库,有兴趣的小伙伴可以通过公众号dg36获取克隆地址。


以上就是跨平台代码的3种组织方式的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号