Deserialisierung von Arrays



  • Ich kommuniziere gerade mit Smart Buttons und erhalte durch einen Socket die Packetdaten in einer Byte-Folge. Das Info Paket aus dem entsprechenden SDK sieht folgendermaßen aus:

    typedef struct 
    {
    	uint8_t opcode;						// Zur Unterscheidung der Paketdaten 
    	// ...
    	uint8_t current_pending_connections;
    	uint8_t currently_no_space_for_new_connection;
    	uint16_t nb_verified_buttons;
    	uint8_t bd_addr_of_verified_buttons[0][6];
    } EvtGetInfoResponse;					// 1 Byte aligned
    

    Nicht zu unrecht motzt hier der Compiler über das [0][6] Array. Die Arraygröße ist hierbei abhängig von nb_verified_buttons

    Das Problem ist hierbei folgendes. Eigentlich könnte man ja uint8_t bd_addr_of_verified_buttons[N][6]; setzen. Aber dann würde sich die Größe des Structs ändern. Und diese nehme ich zur Überprüfung der eingehenden Daten. Ich überprüfe erstens ob der Opcode stimmt und zweitens ob die Anzahl der empfangenen Daten größer gleich sizeof(EvtGetInfoResponse) ist. Ist dies der Fall so lege ich einen EvtGetInfoResponse Zeiger auf die empfangenen Daten.

    Wie würdet ihr das sauber lösen ohne die Warnung zu ignorieren?



  • Kann denn der Fall nb_verified_buttons = 0 vorkommen?
    Ansonsten kannst du ja uint8_t bd_addr_of_verified_buttons[1][6] benutzen (also mindestens immer ein weiterer Datensatz).

    Welchen Compiler verwendest du denn? Seit C99 gibt es Flexible Array Member und einige C++ Compiler unterstützen dies auch, also uint8_t bd_addr_of_verified_buttons[][6].



  • @Th69 sagte in Deserialisierung von Arrays:

    Kann denn der Fall nb_verified_buttons = 0 vorkommen?

    Leider ja

    Welchen Compiler verwendest du denn?

    Visual C++ 2019 (v142)

    VLAs mag der C++ Compiler nicht. Mal schauen was der C Compiler sagt.



  • Hast du denn die MS-Extensions aktiviert? s.a. Arrays (C++): Stack declarations:

    A zero-sized array is legal only when the array is the last field in a struct or union and when the Microsoft extensions are enabled (/Za or /permissive- isn't set).



  • @Th69 sagte in Deserialisierung von Arrays:

    Hast du denn die MS-Extensions aktiviert?

    Ich habe die Optionen eingestellt, aber trotzdem kommt die Warnung C4200.

    Nutze ich VLA innerhalb einer C Datei, so funktioniert dies auch nicht. Es ist zum Mäuse melken...


    Ich glaube das beste ist aktuell das Struct in zwei Kopien aufzusplitten.

    In dem ersten Struct, nennen wir es EvtGetInfoResponse0, kommentiere ich die Zeile uint8_t bd_addr_of_verified_buttons[0][6]; aus.

    Im dem zweiten Struct setze ich die Arraygröße auf 1 und überprüfe nur rudimentär die Anzahl der empfangenen Bytes. Die benötigten Bytes dürfte dann mindestens sizeof(EvtGetInfoResponse) + nb_verified_buttons * 6 sein

    Und über die Falle Zeiger = 2D Array möchte ich nicht mehr stolpern.

    BTW manuelle Speicherreservierung dürfte halt wg. dem 1 Byte Aligment kompliziert sein.



  • Du könntest ja folgendes zum Unterdrücken der Warnung verwenden

    #pragma warning( push )
    #pragma warning( disable : 4200 )
    // ...
    #pragma warning( pop )
    

    Laut warning pragma müßte auch einfach nur folgendes gehen:

    #pragma warning( suppress: 4200 )
    // ...
    


  • @Quiche-Lorraine sagte in Deserialisierung von Arrays:

    Wie würdet ihr das sauber lösen ohne die Warnung zu ignorieren?

    Eine weitere Lösung wäre, das Paket in dem Fall als zwei separate Typen zu interpretieren. Einmal als struct ohne bd_addr_of_verified_buttons und falls nb_verified_buttons => 1 gilt, liegt dahinter eben noch ein Array variabler Länge, mit dessen Adresse man z.B. einen uint8_t (*nb_verified_buttons)[6] initialisieren könnte (Pointer auf ein Array mit uint8_t[6]-Elementen), um darauf zuzugreifen. Länge dieses Arrays ist dann response.nb_verified_buttons.



  • #include <stdint.h>
    
    typedef struct 
    {
    	uint8_t opcode;						// Zur Unterscheidung der Paketdaten 
    	// ...
    	uint8_t current_pending_connections;
    	uint8_t currently_no_space_for_new_connection;
    	uint16_t nb_verified_buttons;
    	uint8_t bd_addr_of_verified_buttons[1][6];
    } EvtGetInfoResponse;		
    
    static unsigned const EvtGetInfoResponseBaseSize = sizeof(EvtGetInfoResponse) - sizeof(((EvtGetInfoResponse*)0)->bd_addr_of_verified_buttons);
    


  • Danke für die vielen Tipps!

    Ich habe dies jetzt in zwei seperaten Typen unterteilt und damit funktioniert es.


Log in to reply