2014-03-25 65 views
8

我將一些代碼移植到Darwin OS X中,並且作爲更改的一部分,我們從gcc轉到clang編譯器。如何從std :: basic_ios獲取文件描述符以在OS X上進行叮噹聲?

在代碼中,有一個從2005年開始的功能,並在互聯網上發佈了幾個地方。它爲幾個不同的GCC版本提供了功能,除了它提供的最後版本,v3.4.0或更高版本外,我已經編輯了所有版本。代碼取決於兩個GCC特定類:__gnu_cxx::stdio_filebuf__gnu_cxx::stdio_sync_filebuf

//! Similar to fileno(3), but taking a C++ stream as argument instead of a 
//! FILE*. Note that there is no way for the library to track what you do with 
//! the descriptor, so be careful. 
//! \return The integer file descriptor associated with the stream, or -1 if 
//! that stream is invalid. In the latter case, for the sake of keeping the 
//! code as similar to fileno(3), errno is set to EBADF. 
//! \see The <A HREF="http://www.ginac.de/~kreckel/fileno/">upstream page at 
//! http://www.ginac.de/~kreckel/fileno/</A> of this code provides more 
//! detailed information. 
template <typename charT, typename traits> 
inline int 
fileno_hack(const std::basic_ios<charT, traits>& stream) 
{ 
    // Some C++ runtime libraries shipped with ancient GCC, Sun Pro, 
    // Sun WS/Forte 5/6, Compaq C++ supported non-standard file descriptor 
    // access basic_filebuf<>::fd(). Alas, starting from GCC 3.1, the GNU C++ 
    // runtime removes all non-standard std::filebuf methods and provides an 
    // extension template class __gnu_cxx::stdio_filebuf on all systems where 
    // that appears to make sense (i.e. at least all Unix systems). Starting 
    // from GCC 3.4, there is an __gnu_cxx::stdio_sync_filebuf, in addition. 
    // Sorry, darling, I must get brutal to fetch the darn file descriptor! 
    // Please complain to your compiler/libstdc++ vendor... 
#if defined(__GLIBCXX__) || defined(__GLIBCPP__) 
    // OK, stop reading here, because it's getting obscene. Cross fingers! 
# if defined(__GLIBCXX__) // >= GCC 3.4.0 
    // This applies to cin, cout and cerr when not synced with stdio: 
    typedef __gnu_cxx::stdio_filebuf<charT, traits> unix_filebuf_t; 
    unix_filebuf_t* fbuf = dynamic_cast<unix_filebuf_t*>(stream.rdbuf()); 
    if (fbuf != NULL) { 
    return fbuf->fd(); 
    } 

    // This applies to filestreams: 
    typedef std::basic_filebuf<charT, traits> filebuf_t; 
    filebuf_t* bbuf = dynamic_cast<filebuf_t*>(stream.rdbuf()); 
    if (bbuf != NULL) { 
    // This subclass is only there for accessing the FILE*. Ouuwww, sucks! 
    struct my_filebuf : public std::basic_filebuf<charT, traits> { 
     int fd() { return this->_M_file.fd(); } 
    }; 
    return static_cast<my_filebuf*>(bbuf)->fd(); 
    } 

    // This applies to cin, cout and cerr when synced with stdio: 
    typedef __gnu_cxx::stdio_sync_filebuf<charT, traits> sync_filebuf_t; 
    sync_filebuf_t* sbuf = dynamic_cast<sync_filebuf_t*>(stream.rdbuf()); 
    if (sbuf != NULL) { 
    return fileno(sbuf->file()); 
    } 
# endif 
#else 
# error "Does anybody know how to fetch the bloody file descriptor?" 
    return stream.rdbuf()->fd(); // Maybe a good start? 
#endif 

    errno = EBADF; 
    return -1; 
} 

的問題是,對鐺5.1 OS X小牛隊,這將是對計算的std::basic_ios文件描述符的方式嗎?

+1

我可以告訴你,在使用C++運行時很可能是LLVM項目[libC++](http://libcxx.llvm.org/index.html),並且它的'basic_filebuf'類似乎包裝stdio'FILE'而不是直接使用OS級文件描述符。但是我沒有辦法從'filebuf'中提取'FILE'或者從已經打開的'FILE'中創建一個'filebuf'。也許有人比我更聰明。 – zwol

+0

你有周圍嗎?你做了什麼? – Paulo1205

+0

@ Paulo1205問題從未解決,我的調用代碼只處理'return -1'和'errno == EBADF'的情況。 – WilliamKF

回答

2

如果你不介意讓你的手真髒亂抓一輪民營實施細則下面的代碼工作:

#include <iostream> 
#include <fstream> 

// Generate a static data member of type Tag::type in which to store 
// the address of a private member. It is crucial that Tag does not 
// depend on the /value/ of the the stored address in any way so that 
// we can access it from ordinary code without directly touching 
// private data. 
template < class Tag > 
struct stowed 
{ 
    static typename Tag::type value; 
}; 

template < class Tag > 
typename Tag::type stowed<Tag>::value; 

// Generate a static data member whose constructor initializes 
// stowed<Tag>::value. This type will only be named in an explicit 
// instantiation, where it is legal to pass the address of a private 
// member. 
template < class Tag, typename Tag::type x > 
struct stow_private 
{ 
    stow_private() { stowed<Tag>::value = x; } 
    static stow_private instance; 
}; 
template < class Tag, typename Tag::type x > 
stow_private< Tag, x > stow_private< Tag, x >::instance; 

struct filebuf_file { typedef FILE*(std::filebuf::*type); }; 
template struct stow_private< filebuf_file, &std::filebuf::__file_ >; 

FILE* c_file(std::filebuf& fb) 
{ 
    return fb.*stowed<filebuf_file>::value; 
} 

int main(int argc, const char * argv[]) 
{ 
    std::ofstream fs("test.txt"); 
    FILE* file = c_file(*fs.rdbuf()); 
    std::cout << file->_file << "\n"; 
    return 0; 
} 
相關問題