mikrocontroller.net

Forum: PC-Programmierung [C++] Klasse von std::FILE ableiten


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von In the Dessert I can't remember my Name (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Gentle(wo)man,

beim C++ üben habe ich die Macht der Ableitung erfahren. Jetzt versuche 
ich gerade eine Klasse für Dateien zu schreiben. Da dachte ich, ich 
leite einfach von std::FILE ab.
 
#include <cstdio>
#include <string>

using namespace std;

class Datei: public FILE {
public:
        ~Datei() {
                fclose(this);
        }
        Datei(string s) {
                *this = *static_cast<Datei*>(fopen(s.c_str(), "w"));
        }
};

int main() {
        Datei d("hallo.txt");
        fprintf(&d, "Hallo Welt!");
        return 0;
}

Leider bekomme ich zur Laufzeit einen Fehler (nur mit GNU C++)
Fatal error: glibc detected an invalid stdio handle

Mit OpenWatcom 1.9 compiliert wird die Datei zwar ohne Fehlermeldung 
erstellt, bleibt aber leer.

Wie gehe ich das richtig an, so dass ich mit einer von std::FILE 
abgeleiteten Klasse arbeiten kann, bzw. wie initialisiert man das ganze?

von Dirk K. (merciless)


Bewertung
0 lesenswert
nicht lesenswert
In the Dessert I can't remember my Name schrieb:
> Wie gehe ich das richtig an

Lass es bleiben, ist kein guter Stil.
Das ist eine bessere Lösung:
https://de.wikipedia.org/wiki/Komposition_an_Stelle_von_Vererbung

Und ein gutes Buch über C++ würde dir auch helfen,
Konstruktoren und den this-Pointer zu verstehen.

merciless

von In the Dessert I can't remember my Name (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Dirk K. schrieb:
> ein gutes Buch über C++ würde dir auch helfen

Danke für Dein schonungsloses Feedback. Welches Buch kannst Du 
empfehlen?

von Gelegenheitscoder (Gast)


Bewertung
0 lesenswert
nicht lesenswert
glibc will dir sagen, dass du einen Pointer auf eine FILE-Instanz an die 
stdio-Funktionen übergeben hast, die nicht von der glibc erzeugt wurde.

std::FILE ist keine richtige C++-Klasse, sondern nur ein zusätzlicher 
Name für die normale FILE-struct aus der stdio.h von C. Davon eine 
Klasse abzuleiten mag zwar zufälligerweise gehen, ist aber 
typischerweise nicht sinnvoll.

von Yalu X. (yalu) (Moderator)


Bewertung
0 lesenswert
nicht lesenswert
Du kannst eine FILE-Struktur nicht einfach kopieren und hoffen, dass
fprintf, fclose usw. auch auf dieser Kopie funktionieren. In der
Standardbibliothek wird über die offenen Dateien Buch geführt, wobei
jede dieser Dateien wohl durch einen FILE-Pointer in eine Tabelle
repräsentiert ist. Ein Pointer auf dein Datei-Objekt kann darin aber
nicht enthalten sein, da es sich bei diesem Objekt ja nur um eine Kopie
handelt, von der die Standardbibliothek nichts weiß.

Generell sollte auf die Inhalte der FILE-Struktur nicht direkt, sondern
nur über die f*-Funktionen der Standardbibliothek zugegriffen werden.

von mh (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Aus https://en.cppreference.com/w/cpp/io/c
C streams are objects of type std::FILE that can only be accessed and manipulated through pointers of type std::FILE* (Note: while it may be possible to create a local object of type std::FILE by dereferencing and copying a valid std::FILE*, using the address of such copy in the I/O functions is undefined behavior). Each C stream is associated with an external physical device (file, standard input stream, printer, serial port, etc).

Das ist genau das, was du nicht machen darfst.

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
Dein RAII-Ansatz ist im Prinzip richtig, allerdings kannst Du das eben 
nicht mit Vererbung umsetzen, sondern mit Komposition.

Der FILE* Pointer ist ja nur ein Ressource-Handle, deswegen muss man 
überlegen, was Du für eine Semantik haben möchtest, wenn Du 
Datei-Objekte kopierst. Am besten machst Du die Klasse nur 
vertausch-/verschiedbbar, aber nicht kopierbar (analog zu 
std::ofstream).

von Dirk K. (merciless)


Bewertung
2 lesenswert
nicht lesenswert
In the Dessert I can't remember my Name schrieb:
> Dirk K. schrieb:
>> ein gutes Buch über C++ würde dir auch helfen
>
> Danke für Dein schonungsloses Feedback. Welches Buch kannst Du
> empfehlen?

Hier ist eine Liste:
https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282

Mein Tipp: Den Stroustrup nicht als Anfänger lesen,
das ist harter Tobak. Nimm "C++ Primer" für den Einstieg.
Weiterführend Nicolai Josuttis (erklärt STL) und
Scott Meyers (für best practices).

Ich empfehle dir auch, C und C++ weitestgehend zu
trennen, so lange du dich einarbeitest: fprintf() ist C,
in C++ verwendet man dafür streams.

merciless

von mh (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Dirk K. schrieb:
> Ich empfehle dir auch, C und C++ weitestgehend zu
> trennen, so lange du dich einarbeitest: fprintf() ist C,
> in C++ verwendet man dafür streams.

Ich stimme dir zu. Es ist wichtig C und C++ zu trennen. Allerdings 
fprintf genauso C++ wie es C ist. Und aktuell ist es die einzig 
sinnvolle Möglichkeit für die formatierte Ausgabe von Daten im Standard. 
streams haben keinen Vorteil gegenüber den stdio Funktionen, wenn ein 
guter Compiler mit aktivierten Warnungen benutzt wird. Das ändert sich 
zum Glück mit C++20 dank std::format.

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
mh schrieb:
> Dirk K. schrieb:
>> Ich empfehle dir auch, C und C++ weitestgehend zu
>> trennen, so lange du dich einarbeitest: fprintf() ist C,
>> in C++ verwendet man dafür streams.
>
> Ich stimme dir zu. Es ist wichtig C und C++ zu trennen. Allerdings
> fprintf genauso C++ wie es C ist. Und aktuell ist es die einzig
> sinnvolle Möglichkeit für die formatierte Ausgabe von Daten im Standard.
> streams haben keinen Vorteil gegenüber den stdio Funktionen, wenn ein
> guter Compiler mit aktivierten Warnungen benutzt wird. Das ändert sich
> zum Glück mit C++20 dank std::format.

Oder seit C++17 mit:

https://en.cppreference.com/w/cpp/utility/to_chars

von mh (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wilhelm M. schrieb:
> Oder seit C++17 mit:

Das ist kein Ersatz für fprintf. Es ist eine auf einen Wert 
eingeschränkte Variante von printf für Iteratoren. Wenn man etwas 
komplexere Ausgaben hat, hat man schnell die gleichen Probleme wie mit 
den streams.

von Wilhelm M. (wimalopaan)


Bewertung
0 lesenswert
nicht lesenswert
mh schrieb:
> Das ist kein Ersatz für fprintf.

Habe ich nicht behauptet.

Allerdings hast Du gesagt, std::fprintf() wäre die einzige sinnvolle 
Möglichkeit sei, eine formatierte Ausgabe zu erzeugen.

Ich finde std:.to_chars() sehr sinnvoll, weil es per definitionem auch 
die schnellste Möglichkeit sein soll in der stdlibc++.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.