basic_ofstream nur mit char?

OP #1260119
Hallo zusammen,

gcc mag mich irgendwie gar nicht. Folgendes Problem:
1
#include <iostream>
2
#include <fstream>
3

4
using namespace std;
5

6
int main(int argc, char **argv) {
7
    ofstream of("/home/phip/test/a.bin", ios_base::binary);
8
    basic_ofstream<unsigned char> bof("/home/phip/test/b.bin", ios_base::binary);
9

10
    char a[] = {'a', 'b', 'c'};
11
    unsigned char b[] = {0x61, 0x62, 0x63};
12

13
    of.write(a, 3);
14
    bof.write(b, 3);
15

16
    cout << "write of " << (of.good() ? "ok.\n" : "failed.\n");
17
    cout << "write bof " << (bof.good() ? "ok.\n" : "failed.\n");
18
}
liefert
1
write of ok.
2
write bof failed.
Aber warum? Definiere ich bof als basic_ofstream<char>, dann geht's, 
allerdings entspricht das ja auch exakt ofstream. Warum gibt es da ein 
Problem mit unsigned char (Bzw. mit allem anderen als <char>, auch mit 
<short> schlägt write() fehl)?
#1261029
Dein Quelltext sieht m.E. korrekt aus, ich hätte auch
erwartet, dass es klappt.

Ich habe das mal versucht, nachzuvollziehen.
Unter Linux mit dem gcc 4.3.2 habe ich den gleichen Effekt.
Wenn man vor dem Schreiben mit
1
  bof.exceptions( std::ios::eofbit|std::ios::failbit|std::ios::badbit );
einschaltet, daß bei Fehlern eine Ausnahme gewerfen wird, dann
passiert genau das beim Schreiben in basic_ios.h an dieser Stelle:
1
  template<typename _Facet>
2
    inline const _Facet&
3
    __check_facet(const _Facet* __f)
4
    {
5
      if (!__f)
6
  __throw_bad_cast();
7
      return *__f;
8
    }

Weder bei Stroustrup noch bei Josuttis habe ich etwas gesehen,
was da seitens des Aufrufers noch fehlen könnte (außer dass man
bei anderen basic_ofstream<> als char und wchar ggf. explizit die
Datei mit open() öffnen müsste, aber daran liegt es nicht).

Deshalb würde ich mal dreist unterstellen, daß hier die g++-Libs
schwächeln.

Auch wenn es mir schwer fällt zu sagen, aber mit VS2005 klappt
das Schreiben wie erhofft.
Gast #1261196
In

  http://www.unc.edu/depts/case/pgi/pgC++_lib/stdlibcr/cha_3696.htm

steht geschrieben:

  "Users have to provide specialization for char_traits if they use
  other character types than char and wchar_t."

Wahrscheinlich hängt dein Problem damit zusammen. Ich vermute, dass die
Verwendung anderer Typen als char und wchar_t durch Normalsterbliche gar
nicht vorgesehen ist.

Normalsterbliche nehmen IMHO einfach einen ofstream und casten beim
Aufruf von write den unsigned-char-Zeiger in einen char-Zeiger.

Auch ein auf einen anderen Zeichentyp spezialisierter basic_ostream
versagt spätestens dann, wenn man der write-Methode unterschiedliche
Datentypen binär schreiben möchte, was ja durchaus üblich ist. Dann
hilft sowieso nur noch das Casten des Zeigers.

> Auch wenn es mir schwer fällt zu sagen, aber mit VS2005 klappt das
> Schreiben wie erhofft.

Ich vemute, MS hat das char_traits<char> etwas allgemeiner definiert, so
dass es auch für unsigned char funktioniert. Oder sie haben zusätzlich
ein char_traits<unsigned char> definiert. Wenn ich das obige Zitat aber
richtig verstanden habe, ist so etwas im Standard nicht vorgeschrieben.
#1261236
ja, ich dachte auch schon daran, dass die Spezialisierung für
char_traits fehlt und habe die ausprobiert und eingefügt:
1
#include <cstring>
2
namespace std
3
{
4
  template<> struct char_traits<unsigned char>
5
  {
6
    typedef unsigned char   char_type;
7
    typedef int             int_type;
8
    typedef streampos       pos_type;
9
    typedef streamoff       off_type;
10
    typedef mbstate_t       state_type;
11

12
    static void assign( unsigned char &c1, const unsigned char &c2 )
13
    {
14
      c1 = c2;
15
    }
16

17
    static bool eq( const unsigned char &c1, const unsigned char &c2 )
18
    {
19
      return c1==c2;
20
    }
21

22
    static bool lt( const unsigned char &c1, const unsigned char &c2 )
23
    {
24
      return c1<c2;
25
    }
26

27
    static size_t length( const unsigned char *s )
28
    {
29
      return std::strlen( (const char*)s );
30
    }
31

32
    static int compare( const unsigned char *s1,
33
                        const unsigned char *s2,
34
                        size_t n
35
                        )
36
    {
37
      return std::memcmp( (const char*)s1,
38
                          (const char*)s2,
39
                          n
40
                          );
41
    }
42

43
    static unsigned char *copy( const unsigned char *s1,
44
                                const unsigned char *s2,
45
                                size_t n
46
                                )
47
    {
48
      return (unsigned char*)std::memcpy( (char*)s1,
49
                                          (const char*)s2,
50
                                          n
51
                                          );
52
    }
53

54
    static unsigned char *move( const unsigned char *s1,
55
                                const unsigned char *s2,
56
                                size_t n
57
                                )
58
    {
59
      return (unsigned char*)std::memmove( (char*)s1,
60
                                           (const char*)s2,
61
                                           n
62
                                           );
63
    }
64

65
    static unsigned char *assign( unsigned char *s,
66
                                  size_t n,
67
                                  unsigned char c
68
                                  )
69
    {
70
      return (unsigned char*)std::memset( (char*)s, (char)c, n );
71
    }
72

73
    static const unsigned char *find( const unsigned char *s,
74
                                      size_t n,
75
                                      const unsigned char &c
76
                                      )
77
    {
78
      return (const unsigned char *)std::memchr( (const char *)s,
79
                                                 (int)c,
80
                                                 n
81
                                                 );
82
    }
83

84
    static int eof()
85
    {
86
      return EOF;
87
    }
88

89
    static int to_int_type( const unsigned char &c )
90
    {
91
      return (int)c;
92
    }
93

94
    static unsigned char to_char_type( const int &i )
95
    {
96
      return (unsigned char)i;
97
    }
98

99
    static int not_eof( const int &i )
100
    {
101
      return i!=EOF ? i : !EOF;
102
    }
103

104
    static bool eq_int_type( const int &i1, const int &i2 )
105
    {
106
      return i1==i2;
107
    }
108
  };
109
}

Das ändert aber nichts am Verhalten...

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 17 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.