【问题标题】:How to get POSIX strerror_r instead of GNU version?如何获取 POSIX strerror_r 而不是 GNU 版本?
【发布时间】:2011-03-04 09:10:17
【问题描述】:

如何获得 POSIX strerror_r 而不是 GNU 版本?

我在 Ubuntu 8.04 上使用 g++ 和 glibc 2.7 版进行编译(基于其中的内容)。

编辑

在上面的手册页上写着:

glibc 的功能测试宏要求(参见 feature_test_macros(7)):

   The XSI-compliant version of strerror_r() is provided if:
   (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
   Otherwise, the GNU-specific version is provided.

然后在feature_test_macros(7)

   If no feature test macros are explicitly defined, then the following feature
   test macros are defined by default: _BSD_SOURCE, _SVID_SOURCE, _POSIX_SOURCE,
   and _POSIX_C_SOURCE=200809L (200112L in glibc versions before 2.10; 199506L in
   glibc versions before 2.4; 199309L in glibc versions before 2.1).

所以我应该得到 POSIX 版本,但我得到的是 GNU 版本。

【问题讨论】:

  • 您确定没有任何头文件或 3. 派对头文件定义例如_GNU_SOURCE ?

标签: ubuntu g++ posix glibc


【解决方案1】:

来自标题string.h

/* Reentrant version of `strerror'.
   There are 2 flavors of `strerror_r', GNU which returns the string
   and may or may not use the supplied temporary buffer and POSIX one
   which fills the string into the buffer.
   To use the POSIX version, -D_XOPEN_SOURCE=600 or -D_POSIX_C_SOURCE=200112L
   without -D_GNU_SOURCE is needed, otherwise the GNU version is
   preferred.  */

注意,使用 GNU 扩展时要小心,最后打开它们 (_GNU_SOURCE),然后再包含您希望它影响的标头(或策略性地取消定义)。不过,如果不使用 GNU 扩展,则无需担心。

一般来说,如果 GNU 在默认行为中偏离 POSIX,您会在标题中看到一些 cmets 来指示您如何获得 POSIX 行为。它也(通常)记录在 glibc 手册中,但这并不总是能出现在高度浓缩的手册页中。

编辑

试试这个简单的测试:

#include <string.h>
#ifdef _GNU_SOURCE
#error "Something turned it on!"
#endif

或者更直接

#ifdef _GNU_SOURCE
#undef _GNU_SOURCE
#endif
#include <string.h>

如果定义了 _POSIX_C_SOURCE={version},您应该拥有 POSIX 版本,除非其他原因导致 GNU 版本受到青睐。

我唯一能想到的就是_GNU_SOURCE。我确定这不在您的命令行标志上,您会看到它。可能是包含的另一个库已将其打开。

这就是我在请求支持 POSIX 实现时扩展“棘手”的意思,即使您不是打开它们的人。

编辑

如果 _GNU_SOURCE 正在开启某些东西(我不记得 boost 是否开启,我使用 c++ 的次数几乎没有使用 C 的次数),您可能希望允许它这样做。您可以从命令行使用--undef "[macro]" -U[macro]。但是,如果库代码如下所示,这将不起作用:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <stdio.h>
#include <string.h>

#ifdef _GNU_SOURCE
#error "It didn't work"
#endif

int main(void)
{
   return 0;
}

问题是,当您的代码实际包含 string.h 时,其他东西已经打开了扩展并包含了它。包含警卫自然会阻止您将其包含两次。

尝试在任何东西之前明确关闭_GNU_SOURCE 并包括string.h。这可以防止其他库打开这些扩展。但是,如果没有它们,这些库可能无法工作。有些代码只是“预期”GNU 行为,不包括回退到 POSIX。

我对没有asprintf() 的库代码也有类似的挫败感。

【讨论】:

  • 我不明白的是,在文档中它说 _POSIX_C_SOURCE=200112L 是默认定义的(请参阅对我的 OP 的编辑),所以我不明白为什么我会得到GNU 版本。
  • 我尝试了第一个,显然有些东西正在打开它。我的代码中没有任何东西可以打开它,所以我假设它必须来自 glibc、stdlib++ ( STL ) 或 Boost。有没有办法从命令行全局取消定义?
  • 我运行了一个测试,其中我检查了_GNU_SOURCE 作为文件中的第一个语句,显然它是由 g++ 默认定义的。问题是,是否会从命令行中断东西将其关闭...
  • @RobertS.Branes 为我解决 libstdc++ 的问题。
  • g++ undeed 默认开启_GNU_SOURCE,手动关闭会破坏libstdc++。显然,libstdc++ 依赖于其他头文件中的特定定义,这些定义仅在定义 _GNU_SOURCE 时出现。
【解决方案2】:

这是一个特定于实现的解决方法。

#ifdef __cplusplus
extern "C"
    {
#endif
    extern 
    int __xpg_strerror_r(int errcode,char* buffer,size_t length);
    #define strerror_r __xpg_strerror_r

#ifdef __cplusplus
    }
#endif

【讨论】:

  • 当我们谈论用户态时为什么要给出你的内核版本?
【解决方案3】:

虽然标准并不要求它是线程安全的,但我无法想象一个理智的人会以任何方式编写非线程安全的strerror。人们在做什么,gunzip 运行时的错误字符串之类的?!一个好的 strerror 应该返回一个指向标准库中的字符串常量的指针,或者从语言环境消息文件返回一个指向常量 mmap 的内存。

抱歉,这不是一个真正的答案,但如果您不关心绝对的理论可移植性,您可以检查并查看您关心的所有实现是否具有健全的 strerror 行为,如果是,请使用它而是。

【讨论】:

  • 你很有趣。第二句话让我大笑。哇,我简直不敢相信我刚刚输入了 LOL'ing,该死的又来了。你会认为我 13 岁时会打字。呸,一晚上可能喝了太多啤酒和太多的单元测试。
  • 另一个像这样带有荒谬_r 变体的函数是readdir。有一个非常好的DIR 结构来包含缓冲区(或者如果人们真的坚持从多个线程读取单个DIR,则指向一个动态分配的每个线程缓冲区的指针)并且绝对没有理由添加readdir_r (界面笨拙)。
  • 手册页甚至列出了示例:“未知错误 NNN”。这就是没有翻译。
  • FWIW 标准已更新为要求 readdir 是线程安全的。希望strerror成为下一个。
  • @o11c:确实,为无效错误号生成的消息是返回非不可变字符串的明显情况。我提出的标准化折衷方案是要求 strerror 仅在传递给它的错误号有效时才是线程安全的。
猜你喜欢
  • 1970-01-01
  • 2017-05-14
  • 1970-01-01
  • 2017-03-04
  • 2021-02-16
  • 2021-10-20
  • 2018-05-03
  • 2015-10-17
  • 1970-01-01
相关资源
最近更新 更多