c++ - How to get a file descriptor from a std::basic_ios for clang on OS X? -
i'm porting code darwin os x , part of change, go gcc clang compiler.
in code, there function dating 2005 , posted several places on internet. provides functionality several different old versions of gcc, i've edited out last offers, v3.4.0 or later. code depends upon 2 gcc specific classes: __gnu_cxx::stdio_filebuf
, __gnu_cxx::stdio_sync_filebuf
.
//! similar fileno(3), taking c++ stream argument instead of //! file*. note there no way library track //! descriptor, careful. //! \return integer file descriptor associated stream, or -1 if //! stream invalid. in latter case, sake of keeping //! code similar fileno(3), errno set ebadf. //! \see <a href="http://www.ginac.de/~kreckel/fileno/">upstream page @ //! http://www.ginac.de/~kreckel/fileno/</a> of code provides more //! detailed information. template <typename chart, typename traits> inline int fileno_hack(const std::basic_ios<chart, traits>& stream) { // c++ runtime libraries shipped ancient gcc, sun pro, // sun ws/forte 5/6, compaq c++ supported non-standard file descriptor // access basic_filebuf<>::fd(). alas, starting gcc 3.1, gnu c++ // runtime removes non-standard std::filebuf methods , provides // extension template class __gnu_cxx::stdio_filebuf on systems // appears make sense (i.e. @ least unix systems). starting // gcc 3.4, there __gnu_cxx::stdio_sync_filebuf, in addition. // sorry, darling, must brutal fetch darn file descriptor! // please complain 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 // applies cin, cout , cerr when not synced 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(); } // applies filestreams: typedef std::basic_filebuf<chart, traits> filebuf_t; filebuf_t* bbuf = dynamic_cast<filebuf_t*>(stream.rdbuf()); if (bbuf != null) { // subclass there accessing 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(); } // applies cin, cout , cerr when synced 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 know how fetch bloody file descriptor?" return stream.rdbuf()->fd(); // maybe start? #endif errno = ebadf; return -1; }
the question is, clang 5.1 on os x mavericks, way computed file descriptor std::basic_ios
?
if don't mind getting hands dirty poking round in private implementation details following code works:
#include <iostream> #include <fstream> // generate static data member of type tag::type in store // address of private member. crucial tag not // depend on /value/ of the stored address in way // can access 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 static data member constructor initializes // stowed< tag >::value. type named in explicit // instantiation, legal pass address of 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; }
Comments
Post a Comment