strerror_r 在 Alpine Linux 上的声明不正确
strerror_r is incorrectly declared on Alpine Linux
我在日志记录辅助函数中使用 strerror_r。如手册页所述,此函数有两个版本。 POSIX 版本 returns 一个 int。 GNU版本returns一个字符串(char*).
因此,为了让我的 C++ 代码更具可移植性,我有一段与此类似的代码:
char buffer[1000];
int size = 1000;
int result = 0;
char* msg = buffer;
buffer[0] = '[=12=]';
#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 的唯一声明版本是 returns 一个 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] = '[=11=]';
char* msg = check_error(strerror_r(err, buffer, sizeof buffer), buffer, err);
LogToFile(msg);
我在日志记录辅助函数中使用 strerror_r。如手册页所述,此函数有两个版本。 POSIX 版本 returns 一个 int。 GNU版本returns一个字符串(char*).
因此,为了让我的 C++ 代码更具可移植性,我有一段与此类似的代码:
char buffer[1000];
int size = 1000;
int result = 0;
char* msg = buffer;
buffer[0] = '[=12=]';
#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 的唯一声明版本是 returns 一个 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] = '[=11=]';
char* msg = check_error(strerror_r(err, buffer, sizeof buffer), buffer, err);
LogToFile(msg);