Linux 移植 Windows 的 C++ 代码

conio.h 头文件

移植简述

conio.h 不是 C 标准库中的头文件,在 ISO 和 POSIX 标准中均没有定义。conio 是 Console Input/Output(控制台输入输出)的简写,其中定义了通过控制台进行数据输入和数据输出的函数,主要是一些用户通过按键盘产生的对应操作,比如 getch() 函数等等。大部分 DOS、Windows、Phar Lap、DOSX,OS/2 等平台上的 C 编译器提供了此头文件,UNIX 和 Linux 平台的 C 编译器本身通常不包含此头文件。另外在项目开发中,平时主要是使用 conio.h 这个头文件中的 getch() 函数,即读取键盘字符但是不显示出来(without echo),但是含有 conio.h 的代码在 Linux 下无法直接编译通过,因为 Linux 没有这个头文件。但 Linux 平台下完全可以使用 ncurses 替代 conio.h 头文件,ncurses 支持的 API 可以阅读 官方文档。值得一提的是,ncurses 在 Linux 平台实现了 getch()scanw()getstr() 等函数。

安装依赖

提示

由于 ncurses 不是 Linux 系统默认的库,因此需要安装后才能使用,不同平台的安装命令如下:

  • CentOS/Fedora
1
# yum install -y ncurses ncurses-devel
  • Debian/Ubuntu
1
# apt-get install -y libncurses5-dev libncursesw5-dev

案例代码

提示

ncurses.hcurses.h 这两个头文件是等价的

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <ncurses.h>

using namespace std;

int main() {
cout << ("Hello Wolrd!") << endl;
getch();
return 0;
}

编译说明

由于 ncurses 不是 Linux 系统默认的库,因此编译时需要链接到该库,同时还需要在 C++ 的源文件里添加头文件 ncurses.h,否则编译会失败。

提示

为了可以正常编译使用了 ncurses 的项目代码,不同构建工具的使用说明如下:

若使用 G++ 编译 C++ 项目,则编译命令的示例如下:

1
2
# 编译代码
$ g++ main.cpp -o main -lncurses

若使用 CMake 构建 C++ 项目,则 CMakeLists.txt 配置文件的示例内容如下:

1
2
3
set(CMAKE_CXX_FLAGS "-std=c++11 -lncurses")

add_executable(main main.cpp)

itoa () 函数

移植简述

在 Window 平台里,itoa() 函数可以将整数转换为字符串,其函数的原型如下。Linux 平台中只有 atoi() 函数,并没有对应的 itoa() 函数,但可以使用 sprintf() 或者 snprintf() 函数替代,建议使用更安全的 snprintf()

itoa () 函数

函数原型:char *itoa( int value, char *string,int radix)

函数功能:将整数 value 转换成字符串存入 string 指向的内存空间,radix 为转换时所用基数 (保存到字符串中的数据的进制基数)

函数的参数:value:转换的数据,string:目标字符串的地址,radix:转换后的进制数,可以是 10 进制、16 进制等,范围必须在 2-36 之间

snprintf () 函数

头文件:#include <stdio.h>

函数原型:int snprintf(char *str, size_t size, const char *format, ...)

函数功能:将可变参数 ... 按照 format 格式化成字符串,然后将其复制到 str

函数参数:str:目标字符串,size:拷贝字节数(Bytes),format:格式化字符串,... 可变参数

案例代码

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

using namespace std;

int main() {
int num = 12;
char str[4];
int size = snprintf(str, 4, "%d", num);
cout << "str = " << str << ", size = " << size << endl;
return 0;
}

程序运行的输出结果如下:

1
str = 12, size = 2

strcpy_s () 函数

移植简述

在 Window 平台上,strcpy_s() 函数存在于 #include <cstring> 头文件中。Linux 平台没有该函数,但可以使用 Safe C Library 替代实现。Safe C Library 这个库是在 libc 的基础之上实现了安全的 C11 Annex K 函数,这些函数是它们所缺少的,可以帮助缓解不断增加的安全攻击,特别是缓冲区溢出。

安装依赖

提示

  • 由于 Safe C Library 不是 Linux 系统默认的库,因此需要安装后才能使用,其默认的安装目录如下
  • /usr/local/lib/:包含静态库和动态链接库文件
  • /usr/local/include/libsafec:包所有含头文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 下载文件(这里下载的不是源码压缩包)
# wget https://github.com/rurban/safeclib/releases/download/v02092020/libsafec-02092020.tar.gz

# 解压文件
# tar -xvf libsafec-02092020.tar.gz

# 进入解压目录
# cd libsafec-02092020.0-g6d921f

# 配置
# ./configure

# 编译
# make -j4

# 安装
# make install

值得一提的是,Safe C Library 编译后会单独生成静态库文件 /usr/local/lib/libsafec-3.6.0.a 和动态链接库文件 /usr/local/lib/libsafec-3.6.0.so.3.0.6,其中的 3.6.0 是指版本号。

案例代码

提示

  • strcpy_s() 函数在 Safe C Library 里的 safe_str_lib.h 头文件中声明
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <libsafec/safe_str_lib.h>

using namespace std;

int main() {
char *str = new char[5];
strcpy_s(str, 5, "abcd");
cout << str << endl;
delete[] str;
return 0;
}

编译说明

由于 Safe C Library 不是 Linux 系统默认的库,因此编译时需要链接到该库,同时还需要在 C++ 的源文件里添加头文件 <libsafec/safe_str_lib.h>,否则编译会失败。

提示

  1. 为了可以正常编译使用了 Safe C Library 的项目代码,不同构建工具的使用说明如下所示
  2. 可以将上面构建生成的 libsafec-3.6.0.a 静态库文件和 .h 头文件都拷贝到项目里,这样就可以方便在不同的 Linux 系统编译和运行项目,不用每次切换系统时都要重新安装 Safe C Library

若使用 G++ 编译 C++ 项目,则编译命令的示例如下,请自行更改库文件的版本号:

1
2
3
4
5
# 编译代码
$ g++ main.cpp -o main -L/usr/local/lib/ -l:libsafec-3.6.0.a

# "-L" 参数指定了库文件的目录路径
# "-l:" 参数指定了库文件的文件名

若使用 CMake 构建 C++ 项目,则 CMakeLists.txt 配置文件的示例内容如下,请自行更改库文件的版本号:

1
2
3
link_libraries(/usr/local/lib/libsafec-3.6.0.a)

add_executable(windows_to_linux main.cpp)

函数可变参数宏

移植简述

在 Windows 平台与 Linux 平台,函数可变参数宏定义的语法是不一样的。

案例代码

  • Windows 平台的函数可变参数宏定义的写法如下,使用的是 __VA_ARGS__
1
2
FILE* logfile = fopen("syslog.txt", "w");
#define LOG(format, ...) fprintf(logfile, format, __VA_ARGS__); printf(format, __VA_ARGS__); fflush(logfile);
  • Linux 平台的函数可变参数宏定义写法如下,使用的是 ##__VA_ARGS__
1
2
FILE* logfile = fopen("syslog.txt", "w");
#define LOG(format, ...) fprintf(logfile, format, ##__VA_ARGS__); printf(format, ##__VA_ARGS__); fflush(logfile);