【问题标题】:Difference in stringstream behavior for void* type using libc++ and libstdc++使用 libc++ 和 libstdc++ 的 void* 类型的字符串流行为差异
【发布时间】:2014-04-07 22:11:01
【问题描述】:

以下测试程序根据我使用的是 libc++ 还是 libstdc++ 返回不同的结果。

#include <sstream>
#include <iostream>

int main()
{
    int a = 0;
    void* optr = &a;
    void* iptr;

    std::stringstream ss;
    ss << optr;
    std::cout << ss.str() << '\n';

    ss >> iptr;
    std::cout << iptr << '\n';

    return 0;
}

我在 OSX 10.9.2 上使用来自 Xcode 5 的以下版本的 clang

$ xcrun clang++ --version              
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix

这是使用 libstdc++ 和 libc++ 构建时的测试输出

$ xcrun clang++ test.cpp  <-- libstdc++ version             
$ ./a.out
0x7fff5ec723e8
0x7fff5ec723e8
$ xcrun clang++ test.cpp -stdlib=libc++  <-- libc++ version
$ ./a.out
0x7fff5205125c
0x7fff5

这是 stringstream 的 libc++ 实现中的错误吗? void* 与 stringstream 的这种用法是有效的 C++ 吗?

谢谢!

【问题讨论】:

  • [locale.num.get] 似乎是指定这一点的标准部分。似乎说ss &gt;&gt; iptr 的行为应该像sscanf%p 但AFAICS 它实际上并没有指定这一点。 “第 3 阶段”描述似乎涵盖了整数和浮点类型,但它忽略了void *sscanf(ss.str().c_str(), "%p", &amp;iptr); 有效吗?
  • @MattMcNabb:我刚刚用 clang-503.0.38(基于 LLVM 3.4svn)进行了测试,sscanf(ss.str().c_str(), "%p", &amp;iptr); 确实对我有用。

标签: c++ llvm stringstream libc++


【解决方案1】:

是的!这是 libc++ 中的一个错误,可能是在 __sscanf_l 的实现中(一些 scanf 看起来相似,应该考虑到语言环境)。 libstdc++ 的实现要简单得多。

// libc++

template <class _CharT, class _InputIterator>
_InputIterator
num_get<_CharT, _InputIterator>::do_get(iter_type __b, iter_type __e,
                                        ios_base& __iob,
                                        ios_base::iostate& __err,
                                        void*& __v) const
{
    // Stage 1
    int __base = 16;
    // Stage 2
    char_type __atoms[26];
    char_type __thousands_sep = 0;
    string __grouping;
    use_facet<ctype<_CharT> >(__iob.getloc()).widen(__num_get_base::__src,
                                                    __num_get_base::__src + 26, __atoms);
    string __buf;
    __buf.resize(__buf.capacity());
    char* __a = &__buf[0];
    char* __a_end = __a;
    unsigned __g[__num_get_base::__num_get_buf_sz];
    unsigned* __g_end = __g;
    unsigned __dc = 0;
    for (; __b != __e; ++__b)
    {
        if (__a_end == __a + __buf.size())
        {
            size_t __tmp = __buf.size();
            __buf.resize(2*__buf.size());
            __buf.resize(__buf.capacity());
            __a = &__buf[0];
            __a_end = __a + __tmp;
        }
        if (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc,
                                    __thousands_sep, __grouping,
                                    __g, __g_end, __atoms))
            break;
    }
    // Stage 3
    __a[sizeof(__a)-1] = 0;
#ifdef _LIBCPP_LOCALE__L_EXTENSIONS
    if (sscanf_l(__a, _LIBCPP_GET_C_LOCALE, "%p", &__v) != 1)
#else
    if (__sscanf_l(__a, __cloc(), "%p", &__v) != 1)
#endif
        __err = ios_base::failbit;
    // EOF checked
    if (__b == __e)
        __err |= ios_base::eofbit;
    return __b;
}

// libstdc++

template<typename _CharT, typename _InIter>
_InIter
num_get<_CharT, _InIter>::
do_get(iter_type __beg, iter_type __end, ios_base& __io,
       ios_base::iostate& __err, void*& __v) const
{
  // Prepare for hex formatted input.
  typedef ios_base::fmtflags        fmtflags;
  const fmtflags __fmt = __io.flags();
  __io.flags((__fmt & ~ios_base::basefield) | ios_base::hex);

  typedef __gnu_cxx::__conditional_type<(sizeof(void*)
                     <= sizeof(unsigned long)),
unsigned long, unsigned long long>::__type _UIntPtrType;       

  _UIntPtrType __ul;
  __beg = _M_extract_int(__beg, __end, __io, __err, __ul);

  // Reset from hex formatted input.
  __io.flags(__fmt);

  __v = reinterpret_cast<void*>(__ul);
  return __beg;
}

【讨论】:

  • 不过,它们都一样丑陋。不管怎样,这是 libstdc++ 第一次比 libc++ 简单。
  • 其实我觉得 libstdc++ 的解决方案很漂亮,虽然我看不出所有这些下划线的原因......
  • @马萨:The underscores are there for reserved identifiers for the implementation.。这是为了确保代码不会与您的任何代码冲突。
  • @Cornstalks 好的,但是为什么在局部变量中下划线?
  • 我认为局部变量也使用保留名称的原因是它们甚至不能与宏发生冲突。在完全一致的实现中,#define x y#include &lt;vector&gt; 之前不应破坏程序。
【解决方案2】:

从 209305 版开始,这已在 libc++ 中得到修复。

【讨论】:

    猜你喜欢
    • 2017-04-07
    • 2012-02-18
    • 1970-01-01
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-01
    • 2012-01-28
    相关资源
    最近更新 更多