C/C++跨平台SDK开发的注意事项

news/2025/3/1 22:40:59/文章来源:https://www.cnblogs.com/luoweifu/p/18745554
  • 1. C/C++跨平台开发时有哪些值得注意的事项?
    • 1.1. 你知道如何选择C++标准的版本吗?
      • 1.1.1. C++版本说明
      • 1.1.2. 如何选择版本
      • 1.1.3. 最佳实践
    • 1.2. 源代码要如何保存,跨平台和跨IDE时才不会出现中文乱码?
      • 1.2.1. 中文乱码问题与原因分析
      • 1.2.2. 解决策略
    • 1.3. 如何优雅的隔离平台的差异?
      • 1.3.1. 用宏定义隔离平台的差异
      • 1.3.2. 最佳实践
    • 1.4. 接口的参数和返回值可以是任意数据类型吗?
      • 1.4.1. 平台差异
      • 1.4.2. 解决策略
    • 1.5. 如何优雅的实现跨平台的文件系统操作?
      • 1.5.1. 平台的差异
      • 1.5.2. 解决的策略
      • 1.5.3. 路径操作和文件系统的操作
  • 2. 待讨论的命题

开发跨平台SDK如同在多个操作系统的夹缝中走钢丝:你需要同时讨好Linux的严谨、Windows的霸道、macOS的优雅,甚至嵌入式系统的固执。以下是历经实战后的经验沉淀,以及几个值得深思的命题。

1. C/C++跨平台开发时有哪些值得注意的事项?

1.1. 你知道如何选择C++标准的版本吗?

1.1.1. C++版本说明

对于C++跨平台开发来说,选择一个合适的C++版本是最为重要的一件事情。C++跨平台开发最重要的难点之一是解决平台的差异性。C++不同的版本支持的特性不同,版本越新支持的特性越多,很多平台的差异可能在新的标准版本里C++语言层面就帮我们解决了。比如:C++11的chrono模块提供了跨平台的时间处理相关的工具,C++17的filesystem模块提供了跨平台的文件系统相关操作。

1.1.2. 如何选择版本

问题: 在实际项目开发中,C++版本的选择是越高越好吗?

解答: 答案肯定是否定的,要视情况而定。

  • 基于编译器的考虑: 通常我们所说的C++版本,是指C++标准委员会推出的C++大版本,如C++11/C++14/C++17/C++20/C++23等。而这些版本是要由C++编译器来支持的,C++编译器本身也是一个软件,是软件就可能有Bug。C++编译器对这些C++版本的支持也是在持续迭代优化的。越新的C++版本因为支持的时间越短,因此存在Bug的可能性越大;而越老的版本因为编译器支持的时间更长,所以越稳定。
  • 基于应用场景的考虑: 如果是应用层的项目,可以选择最新的C++版本。如果是SDK,SDK本身可能要支持更多的C++版本,建议选择低版本的C++。

1.1.3. 最佳实践

  • 如果是开发新的应用层项目,建议选择较新的稳定版本的C++;结合实际情况,建议选择最新版本的前一到两个大版本,如现在(2025年02月)的最新版本是C++23,建议选择C++17或C++20。
  • 如果是开发底层的SDK项目,SDK本身就希望能支持更多的C++版本,建议选择低版本的C++(如C++11),以覆盖尽可能多的用户。
  • 如果是复杂的老项目:建议维持原有版本,非必要不做升级。

1.2. 源代码要如何保存,跨平台和跨IDE时才不会出现中文乱码?

1.2.1. 中文乱码问题与原因分析

C/C++跨平台开发时,通常需要在多个平台下开发、编译和调试,不同的平台可能会用不同的开发工具。如:

  • Windows: Visual Studio XXXX (XXX表示版本系列,如:2017、2019、2022)
  • Linux: Vim/VSCode + GCC编译器
  • macOS: Xcode

中文乱码的现象和原因:

不同平台编辑和查看代码时,你可能经常会遇到的一个问题是中文乱码(代码注释或常量字符串的中文乱码)。如:Windows下显示正常,Linux(macOS)下显示为乱码;或Linux(macOS)下显示正常,Windows下显示为乱码。

而乱码的本质是文件编码方式不一致

  • Vim、VSCode、XCode保存的文件,默认编码是UTF-8(无BOM标记)。
  • Visual Studio XXXX系列保存的文件,Visual Studio 2022默认是UTF-8 BOM(带BOM标记),2022之前的版本是操作系统的本地编码,中文环境下默认是GBK。

解决思路和方法:

所以,解决问题的思路就是:所有源码文件都统一使用相同的编码格式保存。所有的编辑器、编译器、IDE都要统一编码格式,如统一使用UTF-8编码。

1.2.2. 解决策略

所有源码文件都以UTF-8 BOM的格式保存,任意平台的任意IDE都采用相同的格式保存。

因为到目前为止(2025年02月),各个平台和IDE对UTF-8 BOM格式的支持都很好。

1.3. 如何优雅的隔离平台的差异?

1.3.1. 用宏定义隔离平台的差异

C++跨平台开发,最重要的一件事情就是:抹平平台的差异。不同平台的系统调用接口、文件系统的目录结构等都有所差异,为了实现不同平台的无缝对接,需要对这些差异进行隔离,最常用的方法就是通过预定义宏来实现。

通常有两种方式来实现平台差异的隔离:

  • 操作系统预定义宏,如_WIN32__linux__
  • 编译器预定义宏,如:_MSC_VER__clang__

操作系统预定义宏的通用性比编译器预定义宏更好,通常会采用此种方式。除非我们确实需要使用某个指定编译器的特性时,才使用编译器预定义宏。

1.3.2. 最佳实践

代码实现:

用宏定义隔离平台的差异,实现代码通常会写成如下这样:

#if defined(_WIN32)std::cout << "Windows ";
#elif defined(__APPLE__)std::cout << "Apple " << std::endl;
#elif defined(__ANDROID__)std::cout << "Android" << std::endl;
#elif defined(__linux__)std::cout << "Linux" << std::endl;
#elif defined(__unix__)std::cout << "Unix" << std::endl;
#elsestd::cout << "Unknown platform" << std::endl;
#endif

代码优化:

但这种包含很多宏定义的代码可读性是非常差的,特别是宏定义之间的逻辑代码如果也包含很多if...else...判断时,要看懂代码的逻辑分支是非常痛苦的。

解决策略是:

将这种平台差异的逻辑代码通过源码文件隔离开来。

案例演示:

比如我们有这样一个需求:

跨平台C++项目中想使用localtimegmtime这两个函数的功能。但这两个函数是线程不安全的,想要使用这两个函数的线程安全版本,但Windows和Linux(及类Unix系统)平台的函数名和使用方式是不同的。

  • Windows是 localtime_sgmtime_s
  • Linux是 localtime_rgmtime_r

我们可以定义一个头文件time_util.h,声明两个自定义的函数,对这两个函数进行封装;然后再定义两个源文件time_util_win.cpptime_util_unix.cpp分别进行Windows和Linux(及类Unix系统)下的实现。

1.4. 接口的参数和返回值可以是任意数据类型吗?

1.4.1. 平台差异

C/C++有多种内置的整数类型,如:short、int、long、long long,它们在不同的平台下,所占用的字节大小和表达的数据范围可能是不一样的。我们在进行跨平台C++ SDK开发时,要避免这个问题,应采用定长的数据类型。

1.4.2. 解决策略

在进行跨平台C/C++ SDK开发时,函数的参数和返回值要使用基本数据类型或指针类型。而基本数据类型要采用<stdint.h><cstdint>头文件里的标准整型数据替代内置的数据类型。这些数据类型在不同平台下占用的大小相同。

以下数据类型可以在不同平台下表现一致,对应的大小如下:

数据类型 大小
char 1
bool 1
float 4
double 8
int8_t 1
int16_t 2
int32_t 4
int64_t 8
uint8_t 1
uint16_t 2
uint32_t 4
uint64_t 8

1.5. 如何优雅的实现跨平台的文件系统操作?

1.5.1. 平台的差异

  • Linux的路径分隔符是/,Windows的默认路径分隔符是\,但也支持/
  • Linux(类Unix)平台,文件系统严格区分文件名的大小写。而Windows平台,文件系统不区分文件名的大小写。

1.5.2. 解决的策略

  • 代码中涉及文件或目录的路径时,统一使用/分隔符
  • 头文件、路径(文件名和目录名)、控制台命令等均要严格区分大小写

1.5.3. 路径操作和文件系统的操作

C++17及之后:

  • STL标准库提供了std::filesystem::path类,可以方便的进行路径相关的操作。
  • STL标准库提供了std::filesystem类,可以方便的进行文件相关的操作。

C++17之前:

可以将这些常用的操作自己封装成一系列工具函数,也可以使用开源的第三方库,如boost::filesystem

这里推荐一个我自己实现的轻量级的跨平台filepath类和fileutil类,由于代码较长,这里不详细列出源码,大家可以前往开源项目查看:https://gitee.com/spencer_luo/common_util/blob/master/src/common_util/filepath.h和https://gitee.com/spencer_luo/common_util/blob/master/src/common_util/fileutil.h。

此项目永久开源,大家放心查阅,我们可以简单看一下它的使用方法。

#include "fileutil.h"
#include <iostream>void test_filepath()
{auto path1 = cutl::path("/home/spencer/workspace/common_util/README.md");std::cout << path1.str() << (path1.exists() ? "存在" : "不存在") << ", 是一个"<< (path1.isfile() ? "文件" : "文件夹") << std::endl;std::cout << "父目录: " << path1.dirname() << std::endl;std::cout << "文件名: " << path1.basename() << std::endl;std::cout << "扩展名: " << path1.extension() << std::endl;auto path2 = cutl::path(path1.dirname()).join("LICENSE");std::cout << "LICENSE文件的路径: " << path2 << std::endl;
}

执行结果如下:

/home/spencer/workspace/common_util/README.md存在, 是一个文件
父目录: /home/spencer/workspace/common_util
文件名: README.md
扩展名: .md
LICENSE文件的路径: /home/spencer/workspace/common_util/LICENSE

2. 待讨论的命题

  1. 除了以上这些,你还遇到过哪些跨平台开发中的坑?
  2. 如何平衡抽象层带来的性能损耗与可维护性?
  3. 当某个平台的特殊需求威胁架构设计时,是妥协还是拒绝支持?

请在评论区分享你的血泪史——每个跨平台开发者的伤疤,都是后来者的路标。


SDK开发的更多详细内容:

01. 什么是SDK

02. SDK的设计目标

03. 接口设计与规范

04. 接口注释与接口文档

05. 原理篇:字符集与字符编码(一)

06. 原理篇:字符集与字符编码(二)

07. 原理篇:多字节字符与宽字节字符

08. 原理篇:静态库、动态库与运行库

09. 跨平台:C++标准的版本

10. 跨平台:源码的保存格式与中文乱码问题

11. 跨平台:宏定义隔离平台差异

12. 跨平台:基础数据类型的定义

13. 跨平台:文件系统的操作

14. 跨平台:头文件包含的差异

15. 跨平台:导出接口的定义

16. 跨平台:字节序大端与小端

附录A-计算机术语中成对出现的单词

附录B: 计算机术语中常见的单词缩写


大家好,我是陌尘。

IT从业10年+, 北漂过也深漂过,目前暂定居于杭州,未来不知还会飘向何方。

搞了8年C++,也干过2年前端;用Python写过书,也玩过一点PHP,未来还会折腾更多东西,不死不休。

感谢大家的关注,期待与你一起成长。



【SunLogging】
扫码二维码,关注微信公众号,阅读更多精彩内容

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/891733.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Semantic Kernel:Service内置服务

在SK中内置了一些服务,这些服务可以让我们的应用,简单的实例化调用,便拥有AI能力。以OpenAI为例,SK中内置的OpenAI服务有:内容生成服务:OpenAITextGenerationService聊天服务:OpenAIChatCompletionService文本转图片服务:OpenAITextToImageService声音转文本服务:Open…

扩展NLog加密日志

最近有个需求,要求把日志加密,因为系统一直用的是NLog,所以也只能在这个基础上加密了。本文的用法NLog很早就有了,记录下来,以作后用。NLog加密相对好处理,只需要定义一个TargetWithLayout的子类,重写它的Write方法即可,至于加密算法,可以自己行决定,这样就可以把灵活…

基于stm32的智能门铃-课程设计

介绍 本人的处理器项目课程设计,设计简易,仅为记录学习所用。 代码还未优化,例如全局变量应使用消息队列替换、功能简单可无需使用操作系统等等。 课设题目要求实现功能按键控制蜂鸣器发声 语音控制 手机蓝牙控制 乐曲选择硬件部分 主控 STM32F103C8T6 离线语音识别模块 ASR…

nginx不能进行负载均衡问题的一种情况及其解决方案

本文主要提出一种nginx不能进行负载均衡的情况,并给出解决方案nginx不能进行负载均衡问题的一种情况及其解决方案 1.原因: 由于本地可以启动多个nginx服务器,每个服务器的负载均衡策略可以不同。那么当我们中途更改nginx配置文件并重载的时候,可能会由于之前的误操作,导致新…

HybridCache 混合缓存

asp.net core 9中,引入了HyBridCache,本质上他并不是全新的一种缓存,而以与原来的缓存复合使用。<Project Sdk="Microsoft.NET.Sdk.Web"><PropertyGroup><TargetFramework>net9.0</TargetFramework><Nullable>enable</Nullable&…

让.NET9中的OpenAPI有脸面

前一篇简单说了一下怎么在项目中引入新的OpenAPI,本篇再进一步,看看怎么引入UI界面。主要做法是通过添加/scalar/openapidemo这个静态页面实现,在页面中,引入了scalar的js,关于scalar,请详看https://scalar.com。其他信息与上一篇介绍的差不多。代码如下:using Microsof…

.NET9 中不一样的OpenAPI

在.NET9的第4个预览版里,微软带来了OpenAPI,需要引用Microsoft.AspNetCore.OpenApi,如果想生成本地的API描述文件,需要引用Microsoft.Extensions.ApiDescription.Server。下面是项目文件:<Project Sdk="Microsoft.NET.Sdk.Web"><PropertyGroup><…

2025/2/22课堂记录

dp,树上依赖背包,树上dp,多叉树转二叉树,愚蠢的矿工,宝藏,状压,猛兽军团,国王目录愚蠢的矿工 国王(猛兽军团)愚蠢的矿工这网页稍微有点乱,不过凑合凑合还能看,就是没法提交了而已 首先看到的第一眼,感觉是树上依赖背包 毕竟要挖到某一个节点的宝藏要之前知道根节点…

【Azure Storage Account】利用App Service作为反向代理, 并使用.NET Storage Account SDK实现上传/下载操作

问题描述 在使用Azure上的存储服务 Storage Account 的时候,有时需要代替 它原本提供的域名进行访问,比如默认的域名为:mystorageaccount.blob.core.chinacloudapi.cn, 想转变为 myservice.file.com 。如果使用App Service作为反向代理,我们现在有如下三个疑问: 第一:如…

大胆点!你猜DeepSeek的利润率有多高?

这种一周真是热闹啊,DeepSeek开源周,连续五天(2025年2月24日至28日)开源了5个核心技术项目,覆盖AI模型训练、推理优化、文件系统等多个领域,在今天还放出来了One more thing,直接把自己的利润率放出来了(真不拿用户当外人,哈哈) 接下来让我们一起来看看开源周都带来了…

通过网盘分享的文件:Oracle Database 12c linux版本 安装包

https://pan.baidu.com/s/14n1el1C0v1kbaHpDkw9i6w?pwd=1234 提取码: 1234

CountDownLatch的countDown()方法的底层源码

一、CountDownLatch的构造方法// 创建倒数闩,设置倒数的总数State的值CountDownLatch doneSignal = new CountDownLatch(N);二、countDown() 方法的作用 countDown() 方法的主要作用是将 CountDownLatch 的内部计数器减一。如果计数器减到零,则会唤醒所有等待的线程 三、coun…