在Alpine Linux上错误地声明了strerror_r

sel*_*bie 6 c++ linux g++ alpine-linux

我在日志助手函数中使用strerror_r.如手册页所述,此功能有两个版本.POSIX版本返回一个int.GNU版本返回一个字符串(char*).

因此,为了使我的C++代码更具可移植性,我有一段类似于此的代码:

    char buffer[1000];
    int size = 1000;
    int result = 0;
    char* msg = buffer;
    buffer[0] = '\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);
Run Code Online (Sandbox Code Playgroud)

在上面的代码块中,它将使用任何一个版本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]
Run Code Online (Sandbox Code Playgroud)

哪个映射到此行:

#ifdef _GNU_SOURCE
    msg = strerror_r(err, buffer, size);
Run Code Online (Sandbox Code Playgroud)

/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
Run Code Online (Sandbox Code Playgroud)

看来无论使用什么编译器环境,唯一声明的strerror_r版本是返回int的POSIX版本.这就解释了错误发生的原因.

无需告诉用户他们可以手动#undef _GNU_SOURCE或修改源代码,我如何解决这个问题,以便代码可以继续移植?全局取消定义_GNU_SOURCE可能不是首发,因为这是C++(如上所述,libstdc ++需要).我试图看看是否会有另一个我可以测试的宏组合,但我无法想出任何明显的东西.

Max*_*kin 9

您可以利用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;
}
Run Code Online (Sandbox Code Playgroud)

并且在使用中摆脱条件编译:

char buffer[1000];
buffer[0] = '\0';
char* msg = check_error(strerror_r(err, buffer, sizeof buffer), buffer, err);
LogToFile(msg);
Run Code Online (Sandbox Code Playgroud)