mixing C FILE* and C++ file streams ??

M

Marc Cromme

I would like to ask a question about (good ?) style and possibilities in
mixing C FILE* and C++ file streams.

The background is that I want to use the C libpng library from within C++,
but I would like to open C++ file streams due to easier exception
handeling and safe closure of file ressources.

Question 1:

I open a standard file stream and want to transfer some binary read bits
to a function that accepts a pointer to unsigned char.
The solution I have found is:

std::ifstream pngInput(imgInfo.fileName().c_str(),
std::ios::in | std::ios::binary);
char sig[8];

pngInput.read(sig, 8);

png_check_sig(reinterpret_cast<unsigned char*>(sig), 8);

I consider this cast as a not-so-nice hack, which might fail on some other
platform. However, the obvious - opening a stream of unsigned chars - is
not that easy either, because there are no

char_traits<unsigned char>

defined on the system, that is,

std::basic_ifstream<unsigned char> pngInput(imgInfo.fileName().c_str(),
std::ios::in | std::ios::binary);

fails to compile. Question - is the hack really so bad as I feel, and is
it advisable to define some appropriate specialization of

char_traits<unsigned char> ??

....

Then comes some lines of code which might trow an exception ...

....

Question 2:

Further on I have to use a libpng function that expects a C-style file
pointer of type FILE* , but I have opened a C++ file stream, which I want
to feed it. The naive solution is of course not working, since there is no
conversion operator defined:

// compile time error, since function signature is
// int png_init(void*, FILE*)
png_init_io(png_ptr, pngInput );

// compile time error, no cast from std::ifstream will do
png_init_io(png_ptr, static_cast<FILE*>(pngInput) );

So the question is: is there a portable way to make a cast, or to acess
the underlying C-style file pointer FILE* from a std::ifstream???

If yes, how should this be done in a clean way, such that the file
ressource is properly released in case of exceptions?



I do thank you in advance for considering my C/C++ interfacing questions.

Sincierely, Marc Cromme, engineer
 
J

Jorge L Rivera

A few things,

1. In your context (reading an image into a buffer), casting char to
unsigned char should not be a big deal. I mean, you are reading the
data into an array of char, which is a limitation by the read function.
In reality you are just reading into an array of data which its
sizeof is 1. Therefore, you are trying to read the data into an array
of bytes, whitout reagards to the interpretation. In your case, libpng
is telling you that the data should be an unsigned char, therefore the
need for the cast. You can't escape this, and it is bening in this
case, as sizeof(char) == sizeof(unsigned char), unlike shorts or ints
that would require you to consider endianism...

2. Unless you know exactly what you are doing, defining traits for
types might be very dangerous. If you get it to work, do it,, just be
careful...

3. You are using C++ streams and mixing it with read. This is usually
not a great idea. In this scenario, I fail to see the advantage to using
FILE*, or just file descriptors. I mean, You can always use errno to
give you errors, and basic_stream.read is not any better than ::read (in
my opinion, at least)

I personally would do...


try{
std::string filename = "file.ext";
std::string mode = "r";

struct stat st;
if(stat(filename.c_str(), &st) == -1)
{
throw MyException( std::string("Could not stat file due to: ") +
strerror(errno));
}

FILE* f = fopen(filename.c_str(), mode.c_str());
if(NULL == f)
{
throw MyException( std::string("Error opening file due to: ") +
strerror(errno));
}



int fileSize = st.st_size;
char* buf = new char[fileSize];

int bytesRead = ::fread(f, buf, sizeof(char), fileSize);

if(bytesRead < st.st_size)
{
delete[] buf;
fclose(f);
throw MyException( std::string("Error readingfile due to: ") +
strerror(errno));
}

... Do whatever....
delete[] buf;
fclose(f);

}
catch(MyException& me)
{
}
catch(std::exception& stde)
{
}
catch(...)
{
}



Of course, you can see that this could well be encapsulated in a simple
C++ object, one in which you could make sure that the resources are
properly handled....


Marc said:
I would like to ask a question about (good ?) style and possibilities in
mixing C FILE* and C++ file streams.

The background is that I want to use the C libpng library from within C++,
but I would like to open C++ file streams due to easier exception
handeling and safe closure of file ressources.

Question 1:

I open a standard file stream and want to transfer some binary read bits
to a function that accepts a pointer to unsigned char.
The solution I have found is:

std::ifstream pngInput(imgInfo.fileName().c_str(),
std::ios::in | std::ios::binary);
char sig[8];

pngInput.read(sig, 8);

png_check_sig(reinterpret_cast<unsigned char*>(sig), 8);

I consider this cast as a not-so-nice hack, which might fail on some other
platform. However, the obvious - opening a stream of unsigned chars - is
not that easy either, because there are no

char_traits<unsigned char>

defined on the system, that is,

std::basic_ifstream<unsigned char> pngInput(imgInfo.fileName().c_str(),
std::ios::in | std::ios::binary);

fails to compile. Question - is the hack really so bad as I feel, and is
it advisable to define some appropriate specialization of

char_traits<unsigned char> ??

...

Then comes some lines of code which might trow an exception ...

...

Question 2:

Further on I have to use a libpng function that expects a C-style file
pointer of type FILE* , but I have opened a C++ file stream, which I want
to feed it. The naive solution is of course not working, since there is no
conversion operator defined:

// compile time error, since function signature is
// int png_init(void*, FILE*)
png_init_io(png_ptr, pngInput );

// compile time error, no cast from std::ifstream will do
png_init_io(png_ptr, static_cast<FILE*>(pngInput) );

So the question is: is there a portable way to make a cast, or to acess
the underlying C-style file pointer FILE* from a std::ifstream???

If yes, how should this be done in a clean way, such that the file
ressource is properly released in case of exceptions?



I do thank you in advance for considering my C/C++ interfacing questions.

Sincierely, Marc Cromme, engineer
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top