【问题标题】:strerror_r is incorrectly declared on Alpine Linux在 Alpine Linux 上错误地声明了 strerror_r
【发布时间】:2017-01-31 08:44:03
【问题描述】:

我在日志辅助函数中使用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);

在上面的代码块中,它将使用 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++ 需要)。我正在尝试查看是否还有其他可以测试的宏组合,但我无法提出任何明显的建议。

【问题讨论】:

  • 官方宏检查(根据您链接到的手册页)是(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE,如果提供了 POSIX 版本,则为真,否则提供 GNU 版本。这意味着您的检查应该足以确保提供了 GNU 版本,并且 Alpine Linux 中的 C 库似乎存在错误或过时。
  • 将其包装在您自己的函数中。使其足够灵活以使用任一变体。
  • @n.m.你能详细说明吗?它已经包含在一个函数中......
  • C++ 足够强大,可以在没有宏帮助的情况下决定使用哪个版本的函数。想想函数重载。
  • Alpine Linux 上的 C 库是 musl,如果您使用最新的 Alpine 版本,它就是最新的。

标签: c++ linux g++ alpine


【解决方案1】:

您可以利用 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] = '\0';
char* msg = check_error(strerror_r(err, buffer, sizeof buffer), buffer, err);
LogToFile(msg);

【讨论】:

  • 谢谢。我不知道为什么我自己没有想到这一点。现在看起来很明显。
猜你喜欢
  • 2017-12-30
  • 1970-01-01
  • 2014-05-22
  • 2019-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-10
相关资源
最近更新 更多