ACTUALIZACIÓN: Ver @Jettatura lo que creo que es la mejor respuesta https://stackoverflow.com/a/33612982/225186 (¿solo Linux?).
ORIGINAL:
(probablemente no es multiplataforma, pero simple)
Simplifiying el hack en http://www.ginac.de/~kreckel/fileno/ (respuesta Dvorak), y mirando a esta extensión gcc http://gcc.gnu.org/onlinedocs/gcc-4.6.2/libstdc++/api/a00069.html#a59f78806603c619eafcd4537c920f859, tengo esta solución que funciona en GCC
(4.8 por lo menos) y clang
(al menos 3.3)
#include<fstream>
#include<ext/stdio_filebuf.h>
typedef std::basic_ofstream<char>::__filebuf_type buffer_t;
typedef __gnu_cxx::stdio_filebuf<char> io_buffer_t;
FILE* cfile_impl(buffer_t* const fb){
return (static_cast<io_buffer_t* const>(fb))->file(); //type std::__c_file
}
FILE* cfile(std::ofstream const& ofs){return cfile_impl(ofs.rdbuf());}
FILE* cfile(std::ifstream const& ifs){return cfile_impl(ifs.rdbuf());}
y ca n ser utilizado esto,
int main(){
std::ofstream ofs("file.txt");
fprintf(cfile(ofs), "sample1");
fflush(cfile(ofs)); // ofs << std::flush; doesn't help
ofs << "sample2\n";
}
Limitaciones: (comentarios son bienvenidos)
Me parece que es importante fflush
después fprintf
impresión a std::ofstream
, de lo contrario el "sample2" aparece antes de " sample1 "en el ejemplo anterior. No sé si hay una mejor solución para eso que usar fflush
. Notablemente ofs << flush
no ayuda.
No se puede extraer FILE * de std::stringstream
, ni siquiera sé si es posible. (ver a continuación para una actualización).
Todavía no sé cómo extraer de stderr
de std::cerr
etc., por ejemplo, para su uso en fprintf(stderr, "sample")
, en un código hipotético como éste fprintf(cfile(std::cerr), "sample")
C.
En cuanto a la última limitación, la única solución que encontré es añadir estas sobrecargas:
FILE* cfile(std::ostream const& os){
if(std::ofstream const* ofsP = dynamic_cast<std::ofstream const*>(&os)) return cfile(*ofsP);
if(&os == &std::cerr) return stderr;
if(&os == &std::cout) return stdout;
if(&os == &std::clog) return stderr;
if(dynamic_cast<std::ostringstream const*>(&os) != 0){
throw std::runtime_error("don't know cannot extract FILE pointer from std::ostringstream");
}
return 0; // stream not recognized
}
FILE* cfile(std::istream const& is){
if(std::ifstream const* ifsP = dynamic_cast<std::ifstream const*>(&is)) return cfile(*ifsP);
if(&is == &std::cin) return stdin;
if(dynamic_cast<std::ostringstream const*>(&is) != 0){
throw std::runtime_error("don't know how to extract FILE pointer from std::istringstream");
}
return 0; // stream not recognized
}
intento de manejar iostringstream
Es posible leer con fscanf
de istream
usando fmemopen
, pero eso requiere una gran cantidad de libros y la actualización de la posición de entrada de la secuencia después de cada lectura, si uno quiere combinar C-re anuncios y C++ - lee. No pude convertir esto en una función cfile
como la anterior. (Tal vez una cfile
clase que se mantiene actualizada después de cada lectura es el camino a seguir).
// hack to access the protected member of istreambuf that know the current position
char* access_gptr(std::basic_streambuf<char, std::char_traits<char>>& bs){
struct access_class : std::basic_streambuf<char, std::char_traits<char>>{
char* access_gptr() const{return this->gptr();}
};
return ((access_class*)(&bs))->access_gptr();
}
int main(){
std::istringstream iss("11 22 33");
// read the C++ way
int j1; iss >> j1;
std::cout << j1 << std::endl;
// read the C way
float j2;
char* buf = access_gptr(*iss.rdbuf()); // get current position
size_t buf_size = iss.rdbuf()->in_avail(); // get remaining characters
FILE* file = fmemopen(buf, buf_size, "r"); // open buffer memory as FILE*
fscanf(file, "%f", &j2); // finally!
iss.rdbuf()->pubseekoff(ftell(file), iss.cur, iss.in); // update input stream position from current FILE position.
std::cout << "j2 = " << j2 << std::endl;
// read again the C++ way
int j3; iss >> j3;
std::cout << "j3 = " << j3 << std::endl;
}
Lástima que es solo para BSD; Hubiera sido una gran solución, ya que permitiría usar un ARCHIVO * con cualquier tipo de flujo de C++. –
Usted preguntó "¿por qué?": Porque uno puede tener una implementación en C de la impresión escrita en C que uno puede reutilizar para C++ ostreams (o ofstreams). – alfC
¿Por qué? Porque sobrecargar al operador << es muy conveniente cuando estoy * usando * un objeto, pero formatear la salida de la secuencia puede ser complicado y doloroso. Formatear con fprintf() es compacto y fácil. En otras palabras, me gustaría poder escribir 'out << someObject << anotherObject' pero implementar operator << usando' fprintf (ofp, "% 8.1lf% 2d \ n", doubleVar, intVar) ' – riderBill