我在日志记录帮助程序函数中使用strerror_r。 如手册页所述,此函数有两个版本。 POSIX 版本返回一个 int。 GNU 版本返回一个字符串 (char*)。
因此,为了使我的C++代码更具可移植性,我有一个类似于以下内容的代码块:
char buffer[1000];
int size = 1000;
int result = 0;
char* msg = buffer;
buffer[0] = ' ';
#ifdef _GNU_SOURCE
msg = strerror_r(err, buffer, size);
#else
result = strerror_r(err, buffer, size);
if (result != 0)
{
sprintf(buffer, "unknown error: %d", err);
}
#endif
LogToFile(msg);
在上面的代码块中,它将根据是否存在strerror_r
使用任一版本的_GNU_SOURCE
,这总是由 g++ 设置的,因为 libstdc++ 需要它。 在Mac和Unix的其他变体上,它将使用POSIX版本。
现在这段代码已经运行了很长时间,直到今天。 一个用户试图在Alpine Linux上编译我的代码,今天使用strerror_r
报告了这个编译器错误
main.cpp:16:21 error: invalid conversion from 'int' to 'char*' [-fpermissive]
映射到此行:
#ifdef _GNU_SOURCE
msg = strerror_r(err, buffer, size);
在这个平台上的/usr/include/string.h
达到顶峰,可以揭示以下内容:
#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE)
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE)
|| defined(_BSD_SOURCE)
...
int strerror_r (int, char *, size_t);
...
#endif
看起来无论使用什么编译器环境,strerror_r的唯一声明版本是返回 int 的 POSIX 版本。 因此,这解释了发生错误的原因。
不必告诉用户他们可以手动#undef _GNU_SOURCE
或修改源代码,我该如何解决此问题以使代码可以继续可移植? 全局未定义_GNU_SOURCE可能不是启动器,因为这是C++的(如上所述,libstdc++ 需要)。 我试图看看是否会有另一个我可以测试的宏组合,但我无法想出任何明显的东西。
您可以利用C++函数重载:
char* check_error(int result, char* buffer, int err) {
if(result)
sprintf(buffer, "unknown error: %d", err);
return buffer;
}
char* check_error(char* result, char*, int) {
return result;
}
并摆脱使用中的条件编译:
char buffer[1000];
buffer[0] = ' ';
char* msg = check_error(strerror_r(err, buffer, sizeof buffer), buffer, err);
LogToFile(msg);