Projektstruktur und binäre Datenverarbeitung



  • Hallo an alle,

    ich bin noch ein C Anfänger und habe auch schon einige Bücher gelesen.
    Nun bin ich im Übergang zum Fortgeschrittenen Programmierer
    und daher hab ich einige Fragen, die sich bei meinem aktuellen Projekt stellen:

    Wie sollte man am besten ein Projekt strukturieren?
    Wie viele Dateien (Header- und Codedateien) sind sinnvoll?

    Da ich momentan an einem Spieleserver für ein bereits existierendes Spiel hocke (kein Open-Source)
    habe ich auch ein paar Fragen wegen der Binären Datenverarbeitung:
    Mir passieren immer wieder Speicherfehler (Überlappung, auf Ungültige Speicherbereiche geschrieben, etc.),
    da ich die einzelnen Spielepakete (UDP) auseinander nehmen, Überprüfen und
    anschließend in Variablen speichern muss.
    Kann mir jemand dazu ein paar sichere ANSI-C Funktionen nennen um z.B. zu verhindern, dass zuviel geschrieben wird
    oder um einzelne Bytes (unsigned chars) endianless in Variablen zu speichern?
    Ich hatte schon ein paar Funktionen geschrieben
    die jedoch alle Endian bedingt waren. Und ist eigentlich die Funktion "vsnprintf" ANSI-C und sinnvoll?

    Waren jetzt viele Fragen und ich sage auch schonmal danke,
    an jeden der bis hierhin gelesen hat.
    Wer Codebeispiele, Tutorials oder ähnliches hat kann sie mir auch gerne nennen,
    denn leider fehlen mir dazu die nötigen Stichwörter.

    Vielen Dank im Voraus,

    Gruß Jermuk



  • Jermuk schrieb:

    ich bin noch ein C Anfänger und habe auch schon einige Bücher gelesen.
    Nun bin ich im Übergang zum Fortgeschrittenen Programmierer

    Ich habe dafür länger gebraucht.

    Jermuk schrieb:

    Wie sollte man am besten ein Projekt strukturieren?
    Wie viele Dateien (Header- und Codedateien) sind sinnvoll?

    Zusammengehörende Funktionalitäten zusammen in ein .h/.c Paar, mit klaren möglichst geringen Schnittstellen für Input/Output, evtl. mit klärenden Namensgebungen. Auch solltest du dir vorher im Klaren sein:
    - genau eine oder mehrere Zielplattformen?
    - genau ein oder mehrere Compiler?
    und je nachdem dann die Verwendung von Plattform/Compiler-abhängigem Code.

    Jermuk schrieb:

    Da ich momentan an einem Spieleserver für ein bereits existierendes Spiel hocke (kein Open-Source)
    habe ich auch ein paar Fragen wegen der Binären Datenverarbeitung:
    Mir passieren immer wieder Speicherfehler (Überlappung, auf Ungültige Speicherbereiche geschrieben, etc.),
    da ich die einzelnen Spielepakete (UDP) auseinander nehmen, Überprüfen und
    anschließend in Variablen speichern muss.
    Kann mir jemand dazu ein paar sichere ANSI-C Funktionen nennen um z.B. zu verhindern, dass zuviel geschrieben wird
    oder um einzelne Bytes (unsigned chars) endianless in Variablen zu speichern?
    Ich hatte schon ein paar Funktionen geschrieben
    die jedoch alle Endian bedingt waren. Und ist eigentlich die Funktion "vsnprintf" ANSI-C und sinnvoll?

    hton*/ntoh* (kein ANSI C) mit memcpy (ANSI C) sollte dein Freund sein.
    *sprintf sind STRING-Funktionen (noch nicht mal alle C89), du arbeitest aber binär, d.h. das widerspricht sich.



  • Vielen Vielen Dank für deine Antwort!

    Sorry, hatte vergessen zu erwähnen das ich memcpy schon kannte. vsnprintf kann ich erklären. Ich benötige es zum Zusammensetzten der Rückantworten zum Clienten. Deshalb benutze ich eine merkwürdige Mischung aus C-Strings und binären Daten und darum entstand auch diese Frage 🙂
    Gibt es denn noch andere Möglichkeiten z.B. Integer (z.B. Positionsangaben), Strings (z.B. Namen), Floats, etc. im Speicher hintereinander zu bringen?
    Und da der Server Cross-Plattform sein soll, möchte ich der Einfachheithalber bei ANSI-C bleiben. Wäre es sinnvoll, ein paar Bytes einfach in eine Float Variable zu kopieren oder andersherum (per memcpy) und anschließen per preprocessor-direktiven entweder wenn es im Big-Endian Format ist direkt in den "Binären-String" zu kopieren oder wenn es Little ist per Hand umzukehren oder gibt es da bessere Möglichkeiten?
    Den Tipp mit den zusammengehörenden Funktionalitäten habe ich mir zu Herzen genommen.

    Gruß Jermuk



  • Wutz schrieb:

    Jermuk schrieb:

    ich bin noch ein C Anfänger und habe auch schon einige Bücher gelesen.
    Nun bin ich im Übergang zum Fortgeschrittenen Programmierer

    Ich habe dafür länger gebraucht.

    hab das nicht verfolgt aber bei mir bist noch im beginner state;)



  • Jermuk schrieb:

    Da ich momentan an einem Spieleserver für ein bereits existierendes Spiel hocke (kein Open-Source)
    habe ich auch ein paar Fragen wegen der Binären Datenverarbeitung:
    Mir passieren immer wieder Speicherfehler (Überlappung, auf Ungültige Speicherbereiche geschrieben, etc.),
    da ich die einzelnen Spielepakete (UDP) auseinander nehmen, Überprüfen und
    anschließend in Variablen speichern muss.
    Kann mir jemand dazu ein paar sichere ANSI-C Funktionen nennen um z.B. zu verhindern, dass zuviel geschrieben wird
    oder um einzelne Bytes (unsigned chars) endianless in Variablen zu speichern?

    Ich würde vorschlagen, dass du dir dafür eine struct anlegst, die das Datenpaket enthält und vor allem die Länge. Außerdem sollte sie einen Read- bzw. Write-Pointer besitzen. Das heißt, dass du dein Paket, wie einen Stream behandeln kannst. Dann erstellst du dir noch eine gewisse Menge an Funktionen, die dir Zugriff auf die Datenstruktur geben, aber niemals über die Speichergrenze hinweg gehen.

    In etwa sowas:

    typedef struct IPackage {
       int len;
       int read_position;
       char* data;
    };
    
    /* Zugriffs Funktionen */
    void inp_read(IPackage* p, char* data, size_t len);
    char inp_readBigEndianWord8(IPackage* p);
    short inp_readBigEndianWord16(IPackage* p);
    long inp_readBigEndianWord32(IPackage* p);
    
    /* usw. */
    


  • Vielen Dank für deine Antwort!

    Ich hatte auch schon an sowas ähnliches gedacht, dann jedoch verworfen, da die Pakete von unterschiedlicher Länge sein können d.h. die Länge stellt sich erst beim auslesen heraus. Hab das jetzt mit Funktionen gemacht (Jede Funktion stelt ein Paket dar, der Rückgabewert ist die Anzahl der gelesenen Zeichen). Sollen jetzt z.B. diese EndianRead Funktionen mithilfe von memcpy funktionieren? (memcpy(float test, unsigned char[3], sizeof(float)) (Ich weiß das man es so nicht direkt hinschreiben kann) )

    Gruß Jermuk



  • Jermuk schrieb:

    Ich hatte auch schon an sowas ähnliches gedacht, dann jedoch verworfen, da die Pakete von unterschiedlicher Länge sein können d.h. die Länge stellt sich erst beim auslesen heraus.

    Du hast geschrieben, dass du UDP verwendest. Das bedeutet, dass die Größe des (UDP-)Pakets schon nach dem Auslesen mit recvFrom bekannt sein sollte. Von daher verstehe ich den Einwand nicht.

    Falls ein UDP-Paket mehrere logische Datenpakete enthält, lässt sich das Verfahren, dass ich dir beschrieben habe ebenfalls ohne Probleme anwenden.

    Jermuk schrieb:

    Sollen jetzt z.B. diese EndianRead Funktionen mithilfe von memcpy funktionieren? (memcpy(float test, unsigned char[3], sizeof(float))

    Wie du das implementierst ist egal. Du kannst meistens einfach einen Pointer-Cast machen, derefenrenzieren und dann die Bytes vertauschen.



  • Nicht jede Information steht bei den Paketen an der selben Stelle. Neben festen Werten gibt es auch variable wie z.B. Namen dessen Länge immer ein Byte davor steht. Naja das Problem ist jetzt auf jeden Fall gelöst. Muss jetzt nur noch die Endian Fubktionen schreiben.

    Vielen Dank an alle die mir geholfen haben!

    Gruß Jermuk



  • Jermuk schrieb:

    Nicht jede Information steht bei den Paketen an der selben Stelle. Neben festen Werten gibt es auch variable wie z.B. Namen dessen Länge immer ein Byte davor steht.

    Wo ist das Problem? Das lässt sich doch eben genau mit einem Stream sehr gut abbilden.

    Jermuk schrieb:

    Naja das Problem ist jetzt auf jeden Fall gelöst.

    Na dann...


Anmelden zum Antworten