Pointer sicher casten



  • Ganz kurze Frage: ist folgendes legal?

    struct PacketHeader {
      uint32_t type;
      uint32_t sequence;
    };
    
    struct Packet {
      PacketHeader header;
      struct {
        uint8_t bytes[244];
      } body;
    };
    
    struct BlubPacket {
      PacketHeader header;
      struct {
        float a;
        float b;
        float c;
      } body;
    };
    
    void on_blub_packet(const BlubPacket* packet, int packet_size) {
      if(packet_size == 20) {
        printf("%f, %f, %f", packet->body.a, packet->body.b, packet->body.c);
      }
    }
    
    void on_packet(const Packet* packet, int packet_size) {
      if(packet_size >= 8) {
        if(packet->header.type == BLUB_PACKET_TYPE) {
          on_blub_packet(reinterpret_cast<BlubPacket*>(packet), packet_size);
        }
      }
    }
    
    void recv() {
      const int MAX_BYTES = 252;
      Packet packet;
      int packet_size = read(reinterpret_cast<char*>(&packet), MAX_BYTES);
      on_packet(&packet, packet_size;
    }
    

    Ich lese Daten aus (die Funktion erwartet ein Zeiger auf einen BytePuffer). Jedes Datenpaket enthält einen Header und einen Body. Der Body kann unterschiedliche Größen und Inhalte haben, um welchen Body es sich handelt wird durch die Type Nummer im Header bestimmt.

    Ich habe die Befürchtung das das irgendwann mal ganz böse Fehler verursachen kann ... Wie macht man sowas normalerweise?



  • 1. Nimm size_t für Größen.
    2. Das ist ein ganz widerlicher C/C++-Mischmasch, den du hier machst. Entscheide dich für eine Sprache.
    3. Wenn du Binärdaten auf ein Interface pressen willst, musst du sicherstellen, dass der Compiler dich beim Padding nicht stolpern lässt. Verwende #pragma pack(push,1) vor der Deklaration deiner Strukturen und #pragma pack(pop) danach.



  • zu 1.

    Über signed und unsigned Werte für Größenangaben lässt sich lange streiten. Ich bevorzuge für alles signed zu verwenden (und negative Werte durch asserts überprüfen). Grund: Vorzeichenfehler können so erkannt werden. Negative Werte können bei Fehlern zurückgegeben werden.

    zu 2.

    Wo ist denn da C/C++ mischmasch (auch wenn ich netmal weiß was das bitte heißen soll)? Meinst du das printf und groß geschriebene Konstanten? Das ist nur schnell getippselter Pseudocode ... 😃

    zu 3.

    Das könnte funktionieren, danke!



  • fenrayn schrieb:

    Über signed und unsigned Werte für Größenangaben lässt sich lange streiten. Ich bevorzuge für alles signed zu verwenden (und negative Werte durch asserts überprüfen). Grund: Vorzeichenfehler können so erkannt werden.

    Nein, lässt sich nicht. Für Fehlererkennung haben wir errno , oder noch besser, lass deine Funktionen nur Fehlercodes zurückgeben und echte Werte werden über Zeiger/Referenzen gesetzt. Alles andere verführt dich nur, schludrig zu programmieren.

    POSIX hat genau den gleichen Scheiß gemacht und solche Verbrechen wie recv und strftime in die Welt gesetzt. Und jetzt haben wir den Salat, können keine nicht-NUL-terminierten Timestrings schreiben, und ich muss immer auf < 1 prüfen, wenn was am Socket ankommt.

    Zudem ist Overflow bei unsigned definiert. Bei signed nicht. Und ich gehe davon aus, dass du nicht einer von wenigen Programmierern bist, der in der Lage und willens ist, Overflow-Checks zu implementieren.

    EDIT: Und das gilt eh nur für C. Für C++ macht man Exceptions.

    EDIT 2: Und zur Ehrenrettung von strftime lässt sich sagen, dass die Fehlercoderückgabe nicht der Grund ist, warum keine NNS geschrieben werden können.

    fenrayn schrieb:

    Wo ist denn da C/C++ mischmasch (auch wenn ich netmal weiß was das bitte heißen soll)? Meinst du das printf und groß geschriebene Konstanten? Das ist nur schnell getippselter Pseudocode ... 😃

    struct, printf , Zeigerübergabe, wo sonst Referenzen verwendet werden ...



  • Ich werde meinen uC bestimmt nicht mit Exceptions zumüllen, genauso wie ich kein new/delete benutze und versuche virtual zu vermeiden.

    Wenn ich fürn PC programmiere sieht die Welt schon wieder anders aus ...

    Und was structs angeht: Ich benutze class für Klassen mit Memberfunktionen, und struct eben für Strukturen ohne Memberfunktionen (reine Speicher).

    Meine Frage war nicht ob mir jmd. sein Programmierstil aufschwatzen kann, sondern ob Zeiger-Casts auf andere Typen sicher ist ...



  • dachschaden schrieb:

    2. Das ist ein ganz widerlicher C/C++-Mischmasch, den du hier machst. Entscheide dich für eine Sprache.

    Weil er 2mal reinterpret_cast benutzt oder wieso?



  • Mein Bruder hat mal gesagt: "Programmiersprachen? Ist doch alles dasselbe. Ich benutze alles kreuz und quer solange das erwünschte Ergebnis dabei rauskommt."


Anmelden zum Antworten