2014-04-07 17 views
7

Il seguente programma di test restituisce risultati diversi a seconda che io stia utilizzando libC++ o libstdC++.Differenza nel comportamento stringstream per il tipo void * utilizzando libC++ e 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; 
} 

Sto utilizzando la seguente versione di clang da Xcode 5 su OSX 10.9.2

$ 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 

ecco l'output del test, quando costruito con libstdC++ e libC++

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

Si tratta di un bug nell'implementazione di libC++ di stringstream? Questo uso di void * con stringstream C++ valido?

Grazie!

+2

[locale.num.get] sembra essere la sezione standard specificare questo. Sembra dire che 'ss >> iptr' dovrebbe comportarsi come' sscanf' con '% p', ma AFAICS in realtà non lo specifica. La descrizione "Stage 3" sembra coprire i tipi integrale e float, ma trascura 'void *'. 'Sscanf (ss.str(). C_str(),"% p ", &iptr);' funziona? –

+0

@MattMcNabb: ho appena testato con clang-503.0.38 (basato su LLVM 3.4svn) e 'sscanf (ss. str(). c_str(), "% p", &iptr); 'funziona davvero per me – Cornstalks

risposta

2

Sì! si tratta di un bug in libC++, probabilmente nell'implementazione di __sscanf_l (un po 'similare a scanf che dovrebbe prendere in considerazione le impostazioni locali). L'implemementation di libstdC++ è molto più semplice.

// 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; 
} 

contro

// 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; 
} 
+0

Entrambi sono ugualmente brutti, comunque. Questa è la prima volta che libstdC++ è più semplice di libC++ – refi64

+0

In realtà, penso che libstdC++ soluzione abbastanza bella, anche se non riesco a vedere il ragionamento per tutti quei caratteri di sottolineatura ... – Massa

+0

@Massa: [I caratteri di sottolineatura sono lì per gli identificatori riservati per l'implementazione.] (http://stackoverflow.com/questions/228783/what -are-the-rules-about-using-an-underscore-in-ac-identifier) ​​.Per assicurarsi che il codice non sia in conflitto con alcuno del codice. – Cornstalks

1

Questo è stato risolto in libC++ a partire dalla revisione 209305.