C++跨平台开发注意事项(Win/Linux) 【一】

C++跨平台开发注意事项【一】

I - 概括总述

随着多系统的普及,不少软件面临跨平台的需求,普通 Windows PC 端可以使用的代码,需要在另一个平台下编译和运行。

本文章以 Linux 平台为例,整理了从 Windows 平台上的可编译代码到 Linux 平台上代码移植问题,以及跨平台开发的建议规范与需要注意的事项。

Windows 平台上的 MSVC 编译器容错率比较高,部分代码问题编译器会自动纠正或忽略,但是 Linux 下的 gcc/g++ 比较严格,且运行环境、库不一致,Windows 下可编译的代码,直接在 Linux 下编译会产生很多问题。如何做到隔离区分?

II - 标识与隔离

2.1 - 宏隔离

2.1.1 - 系统宏

代码中的区分平台的宏建议使用 _WIN32 与 __linux__

关于 标识 Windows 的宏,网上存在很多:

WIN32  WIN64 _WIN32  _WIN64 ...

Windows 平台建议使用 _WIN32 ,此宏在操作系统为 x86 和 x64 系统中都会定义,使用 Visual Studio 2019 ,Win11 x64 电脑做开发,不添加自定义宏的情况下,只有 _WIN32_MSC_VER 是有效的。编译 x86 工程或 32 位系统下会额外定义 WIN32,编译 x64 工程则会额外定义 _WIN64

Linux 平台建议使用 __linux__ 系统宏,所有使用 Linux 内核的系统都会默认定义此宏。

示例

#if defined(_WIN32)
std::string port("COM1");
#elif defined(__linux__)
std::string port("/dev/ttyUSB3");
#endif
2.1.2 - 编译器宏

也可以使用编译器宏来区分,Win 平台使用 _MSC_VER 来区分,Linux 平台使用编译器宏 __GNUC__

示例代码

#if defined (_MSC_VER)
p = HeapAlloc(hHeap, dwFlags, dwBytes);
#elif defined(__GNUC__)
p = malloc(sizeof(DataStruct));
#endif
2.1.3 - 注意事项

特定系统的代码隔离使用对应系统的宏,不使用检测另一个系统的宏未定义
示例

#ifndef _WIN32
// code for linux
#endif
//...
#ifndef __linux__
// code for windows
#endif

由于软件的跨平台需求可能不止两个系统,使用 “非此即彼” 的二分方式定义,在有第三个平台的跨平台开发需求时,代码需要做比较多的修改,有可能因修改疏漏造成未知的缺陷,应使用如下方式

#ifdef _WIN32
// code for windows
#endif
//...
#ifdef __linux__
// code for linux
#endif

建议使用平台宏和编译器宏组合的方式来判断

#if defined(_WIN32) || defined(_MSC_VER)
// code for windows
#elif defined(__linux__) || defined(__GNUC__)
// code for linux
#endif

关于更多系统预定义宏,见链接:
https://sourceforge.net/p/predef/wiki/OperatingSystems

2.2 - CMakeList 隔离

if (WIN32)

elseif (UNIX)

endif()

III - 常见平台差异

3.1 - 路径分隔符

代码中涉及文件/目录路径时,使用分隔符 / 替代 \\

Windows 下路径分隔符为 \\ ,Linux 下路径分隔符为 / , 例如

// windows path
std::string pathWin = "D:\\Repository\\MyTest\\test.cpp";
// linux path
std::string pathLinux = "/home/user/Desktop/dev/main.cpp";

多数函数或 API 方法在两种系统下均支持使用 / 作为分隔符。

示例

// 标准库
std::filesystem::exists("D:/Repository/MyTest/test.cpp");
// Qt API
QFile file("D:/Program Files/Typora/config.ini");
if (!file.open(QIODevice::Text | QIODevice::ReadOnly))
{
	qDebug() << "open failed";
	return false;
}

3.2 - 文件系统

包含头文件时,文件名称需使用正确的字母大小写

Windows 平台,文件系统不区分文件名的大小写,以及其目录、控制台和 PowerShell 的命令均不区分大小写。举例,在 Windows 电脑上无法在同一个路径下创建名称分别为 aA 的两个文件或目录。

然而 Linux 下严格区分文件名称的大小写,在同一个目录下,允许字母相同但大小写不同的两个文件存在。

Windows 平台使用错误的大小写依然可以正确访问头文件。

错误举例

// qt 头文件
#include <qlist>
#include <qmap>
// 自定义头文件
#include "predefinedmacros.h"

需更正其大小写

// qt
#include <QList>
#include <QMap>
// 自定义头文件
#include "predefinedMacros.h"

如不清楚 Qt 中文件名的具体大小写,则可使用 Qt 的助手 (Assistant)。索引查找类名,找到后主显示区 Header 处有正确的头文件大小写。

3.3 - 开发环境

3.3.1 - 专属头文件

引入函数或类时,引入对应的头文件

此小节包含两项主要内容,

  • Visual Studio 创建工程时自带的头文件需补充
  • Windows / Linux 平台专属的头文件

创建 VS 解决方案时,默认会包含 VC 相关的一些运行库和头文件,如 cmathstring.hmemory.h 等,Linux 下编译时会因为找不到对应的头文件报错。
在这里插入图片描述
即使用 sqrt 等数学公式时包含 <cmath> ,使用 memcpy 时,需要手动包含一下 <cstring>\,使用了智能指针 shared_ptr 等时,需要手动包含一下 <memory>。

#include <cmath>
#include <cstring>
#include <memory>

另外,平台专属的头文件需要使用宏隔离开,示例

#if defined(_WIN32) || defined(_MSC_VER) || defined(_WIN64)
#include <Windows.h>
#elif defined(__linux__) || defined(__GNUC__)
#include <unistd.h>
#endif
3.3.2 - 专属函数

一些 VC 特殊功能的函数,可使用宏定义
示例

#if _MSC_VER > 1400
#define fgetc _fgetc_nolock
#endif

为了字符串操作安全, VC 提供了一套_s 后缀的接口,为 VC 专属函数,_s 表示 safe (安全),如 sprintf_s 等。可使用如下方式
示例:

#if defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64)
#define SPRINTF sprintf_s
#else
#define SPRINTF sprintf
#endif
// e.g.
SPRINTF(buf, "some string to output %s\n", str.data());

_MSC_VER 是微软内部的一个版本,Visual Studio 2019 中 _MSC_VER 的定义是 1920。 下表为 Visual Studio 版本、 VC 版本 与 _MSC_VER 的对应

_MSC_VERVisual StudioVC++
1910VS2017VC 15.0
1900VS2015VC 14.0
1800VS2013VC 12.0
1700VS 2012VC 11.0

IV - 编译器语法检查

Windows 平台上 MSCV 编译器忽略或者自动纠正的语法错误。

4.1 - 模板使用

使用模板时,需显示声明模板具体类型

错误示例

QList a = temp.split(_SPLIT_CHAR_);
vec.push_back(std::make_pair("key", value));

需更正为

QList<QString> a = temp.split(_SPLIT_CHAR_);
vec.push_back(std::make_pair<QString, double>("key", value));

4.2 - 宏扩展

不使用冗余的宏扩展

宏扩展 ## 用于合成一个标识符,

错误举例

#define BIND_CALLBACK(a,b,c) m_callbackFuncs[a] = std::bind(&##b, c, std::place_holders::_1);
BIND_CALLBACK("customize_callback_1", CallBack::CustomizeCallBack1, this);

Linux 下报错为 毗邻 ‘##’ 无法构建一个有效的标识符。
& 符号,CallBack:: 和后边的函数 b ,为三个标识符,& 为操作符,CallBack:: 为命名空间限定符,所以需要去掉链接符号 ##

#define BIND_CALLBACK(a,b,c) m_callbackFuncs[a] = std::bind(&b, c, std::place_holders::_1);

4.3 - 命名空间限定符

不在类声明中和非静态函数调用处 使用多余的命名空间限定符

1 - 类声明中冗余的命名空间限定符,MSVC 编译器会忽略。

错误示例

class CustomizedClass
{
public:
//...

QString CutomizedClass::Test(const QString & input);
}

类声明中需要去掉 CustomizedClass::

2 - 调用非静态函数是的命名空间限定符

错误示例

return QJsonDocument::QJsonDocument(jsonobj).toJson(QJsonDocument::Compact);

此处需要构造出 QJsonDocument 对象,此函数非静态函数,需要去掉多余的 QJsonDocument::

4.4 - 右值使用

函数调用传参时,不在调用处创建局部变量并使用其地址

函数调用处传入实参处,构造局部对象并取地址,Linux 下会报错,错误为 taking address of rvalue。

错误示例

Func("string", &DataStruct("key1","value1"));

需更改为

DataStruct dt("key1", "value1");
Func("string", &dt);

4.5 - 常量类型指针

使用常量限定类型到非常量限定类型指针传递时,需转换

const 限定类型地址赋值到非 const 限定类型指针。
错误示例

char * ptr = str.data();

发生 const char *char * 的强制转换。需要添加类型转换或者更改类型。

// 1 - 更改目标类型
const char * ptr = str.data();
// 2 - 强转
char * ptr = (char*) str.data();
// 3 - 操作符
char * ptr = const_cast<char*>(str.data());

建议使用第一种
由于布尔类型可与指针发生隐式转换,尽量使用常指针,即使用关键字 const 修饰。

DataStruct(char * str); // 1
DataStruct(bool bval); // 2

DataStruct ds("string"); // 匹配 2

避免在在多个函数重载时会出现匹配错误。

4.6 - 宏函数参数

宏函数使用时,参数个数需要与定义保持一致。

接下文 C++跨平台开发注意事项 (Win/Linux) 【二】

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C跨平台开发技术指南PDF是一本介绍跨平台开发技术的PDF电子书。跨平台开发是指开发在不同操作系统或平台上都能运行的软件或应用程序。由于不同操作系统的底层架构和开发语言不同,跨平台开发技术成为开发者解决不同平台兼容性问题的有效方式。 这本指南提供了详细的跨平台开发技术解决方案和实践经验,帮助开发者理解和应用跨平台开发技术。指南首先介绍了跨平台开发的基本概念和原理,包括平台差异性、可移植性和兼容性等内容。然后,它详细介绍了几种常见的跨平台开发技术,如HTML5、React Native、Flutter和Xamarin等。 在介绍每种技术时,指南会提供相关的开发环境安装和配置教程,以及示例代码和项目实战经验。通过这些实例,开发者可以学习如何使用不同的跨平台开发技术来构建应用程序,从而提高开发效率和应用的用户体验。 此外,该指南还包括了跨平台开发常见问题和解决方案,如性能优化、调试技巧和用户界面设计等。这些内容可以帮助开发者在实际项目中避免常见问题,并更好地应对挑战。 总之,C跨平台开发技术指南PDF是一本有关跨平台开发技术的权威参考书,适用于想要了解和应用跨平台开发技术的开发者。通过学习指南中的内容,开发者可以更好地掌握跨平台开发技术,提高软件开发效率和应用程序的质量。 ### 回答2: 《c 跨平台开发技术指南 pdf》是一本介绍C语言跨平台开发技术的电子书籍。C语言是一种通用的编程语言,具有高效性和灵活性,在跨平台开发中应用广泛。 通过阅读该电子书,读者可以了解C语言如何应用于不同操作系统和平台上,实现跨平台开发。书中可能会介绍一些常见的跨平台开发工具和框架,例如Qt和CMake,通过使用这些工具,开发者可以更加方便地编写跨平台代码。 此外,该书还可能涉及到一些跨平台开发中的注意事项和技巧,例如处理不同操作系统的差异性、处理文件路径问题等等。对于有一定C语言基础的开发者来说,这本书可以提供一些有关跨平台开发的实践经验和建议。 总之,《c 跨平台开发技术指南 pdf》是一本针对想要学习和实践C语言跨平台开发开发者们的指南,可以帮助读者更好地理解并应用C语言在各种平台上进行开发的技术。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值