编写跨平台C++代码(Windows,Linux和Mac OSX)

Lee*_*ley 35 c++ cross-platform

这是我第一次尝试在C++中编写任何稍微复杂的东西,我正在尝试构建一个可以从Objective-C和.NET应用程序接口的共享库(好的,那部分后来......)

我的代码是 -

#ifdef TARGET_OS_MAC
  // Mac Includes Here
#endif

#ifdef __linux__
  // Linux Includes Here
  #error Can't be compiled on Linux yet
#endif

#ifdef _WIN32 || _WIN64
  // Windows Includes Here
  #error Can't be compiled on Windows yet
#endif

#include <iostream>

using namespace std;

bool probe(){
  #ifdef TARGET_OS_MAC
    return probe_macosx();
  #endif
  #ifdef __linux__
    return probe_linux();
  #endif
  #ifdef _WIN32 || _WIN64
    return probe_win();
  #endif
}

bool probe_win(){
  // Windows Probe Code Here
  return true;
}

int main(){

  return 1;
}
Run Code Online (Sandbox Code Playgroud)

我有一个编译器警告,只是untitled: In function ‘bool probe()’:untitled:29: warning: control reaches end of non-void function- 但我也非常感谢人们可以建议如何更好地编写这种代码的任何信息或资源....

sti*_*ijn 46

而不是再次重复自己并再次编写相同的#ifdef ....行,你可能更好地在标题中声明probe()方法,并提供三个不同的源文件,每个平台一个.这样做的好处是,如果添加平台,则无需修改所有现有源,只需添加新文件即可.使用构建系统选择适当的源文件.

结构示例:

include/probe.h
src/arch/win32/probe.cpp
src/arch/linux/probe.cpp
src/arch/mac/probe.cpp
Run Code Online (Sandbox Code Playgroud)

警告是因为probe()不返回值.换句话说,三个#ifdefs中没有一个匹配.

  • 听,听!(1)这增加了代码的清晰度,(2)减少了只为一个平台熟悉的人阅读它的心理努力,(3)不依赖于神秘的非可移植编译器/平台特定标志. (5认同)
  • 这个.也不要依赖编译器定义的平台宏,让你的构建系统定义自己的. (4认同)
  • 我知道它有它的用途,但恕我直言,预处理器应该被删除,这就是所有跨平台编码应该如何完成。 (2认同)
  • 阿门!特定于平台的代码最好由构建系统管理 - 而不是C++预处理器. (2认同)

小智 32

我将解决这个特定的功能:

bool probe() {
#ifdef TARGET_OS_MAC
  return probe_macosx();
#elif defined __linux__
  return probe_linux();
#elif defined _WIN32 || defined _WIN64
  return probe_win();
#else
#error "unknown platform"
#endif
}
Run Code Online (Sandbox Code Playgroud)

以这种方式编写它,作为if-elif-else链,消除了错误,因为没有有效的return语句或命中#error就无法编译.

(我相信WIN32是针对32位和64位Windows定义的,但如果没有查找它,我无法明确告诉你.这样可以简化代码.)


不幸的是,你不能使用#ifdef _WIN32 || _WIN64:请参阅http://codepad.org/3PArXCxo以获取示例错误消息.您可以使用特殊的仅预处理定义的运算符,如上所述.


关于根据功能或整个文件(如建议)拆分平台,您可能想要也可能不希望这样做.它将取决于您的代码的详细信息,例如平台之间共享的内容以及您(或您的团队)最适合保持功能同步的内容,以及其他问题.

此外,您应该在构建系统中处理平台选择,但这并不意味着您不能使用预处理器:对每个平台使用有条件定义的宏(通过makefile或构建系统).实际上,这通常是模板和内联函数最实用的解决方案,这使得它比尝试消除预处理器更灵活.它与整个文件方法完美结合,因此您仍然可以在适当的地方使用它.

您可能希望使用单个配置标头,将所有各种特定于编译器和平台的宏转换为您控制的众所周知的宏.或者您可以将-DBEAKS_PLAT_LINUX添加到编译器命令行 - 通过构建系统 - 来定义该宏(记住使用宏名称的前缀).


ere*_*eOn 5

似乎没有一个TARGET_OS_MAC,__linux__,_WIN32或者_WIN64在您编译代码的时间定义.

所以它就像你的代码一样:

bool probe(){
}
Run Code Online (Sandbox Code Playgroud)

这就是编译器抱怨到达无效函数结束的原因.没有return条款.


此外,对于更一般的问题,这是我在开发多平台/架构软件/库时的指导原则:

避免特定情况.尝试编写与操作系统无关的代码.

在处理系统特定的东西时,尝试将东西包装成"不透明"的类.例如,如果您正在处理文件(Linux和Windows上的不同API),请尝试创建一个File类,该类将嵌入所有逻辑并提供通用接口,无论操作系统如何.如果某个功能在其中一个操作系统上不可用,请处理它:如果该功能对特定操作系统没有意义,那么根本不执行任何操作通常都很好.

简而言之:#ifdef越少越好.无论您的代码多么可移植,请在发布之前在每个平台上进行测试.

祝好运 ;)