1

I'm getting a failure on Linux when calling the read() function on basic_fstream<unsigned char> stream:

basic_fstream<unsigned char> fs;
basic_string<unsigned char> buf(1000, '\0');
fs.open( "/tmp/file.txt", ios::in | ios::binary);
fs.read( &buf[0], 1000);

I traced where it throws: in function __check_facet(const _Facet* __f) it throws __throw_bad_cast() because __f is NULL. The __check_facet() in turn is called from underflow(), with _M_codecvt as the parameter (which is NULL and causes the failure).

The system's locale is UTF8, the code is compiled with --std=c++14. On Windows this works OK.

Can it be corrected somehow?

Al Berger
  • 1,048
  • 14
  • 35
  • 5
    *The C++ library does not provide localte/facets for, what is effectively, an unsigned char stream. The C++ specification does not require the C++ library to do that.* - [this thread](https://stackoverflow.com/questions/55444139/stdbasic-ofstreamstduint8-t-write-fails-at-check-facet) might bring some clarity. – rawrex Jun 25 '21 at 06:36
  • rawrex, thanks for the link. That is, basically, the only solution is using a standard std::fstream? – Al Berger Jun 25 '21 at 06:45
  • 2
    Possible duplicate of [this](https://stackoverflow.com/questions/604431/c-reading-unsigned-char-from-file-stream/604505#604505) – alagner Jun 25 '21 at 06:46
  • @AlBerger I liked the idea of "*your own "binary stream" class*" by [@Emile Cormier](https://stackoverflow.com/users/245265/emile-cormier) in the comments to that thread. – rawrex Jun 25 '21 at 06:49
  • rawrex, yes I saw that comment. I meant that in the wrapper eventually it should be std::ofstream or even C FILE*? – Al Berger Jun 25 '21 at 06:52
  • alagner, thanks, your link is useful too. Seems that basic_fstream is no-go on Linux. – Al Berger Jun 25 '21 at 06:57
  • Remy, I already wanted to write my own facet, but your solution is much simpler. Please post it as an answer. – Al Berger Jun 25 '21 at 07:05
  • 1
    @AlBerger posted – Remy Lebeau Jun 25 '21 at 07:11

1 Answers1

1

The standard library is not required to provide facets or locales for unsigned char. The standard streams are designed only with char (and wchar_t) in mind.

I would suggest using the standard std::ifstream instead. You can read binary data with it, and store it into an unsigned char buffer. You should consider using the standard std::vector container instead of std::basic_string for that buffer.

Try this instead:

ifstream fs("/tmp/file.txt", ios::binary);
vector<unsigned char> buf(1000);
fs.read( reinterpret_cast<char*>(&buf[0]), 1000);

This will work equally on all platforms.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770