Forum: Mikrocontroller und Digitale Elektronik C - struct inklusive CRC - Padding-Bytes


von Simon G. (sigro)


Lesenswert?

Guten Morgen,
wie würdet ihr folgendes Problem sauber in c lösen?
Ich habe eine Konfigurationsstruktur die im FLASH gespeichert werden 
soll; sowohl beim Programmieren als auch im Betrieb.
Ich möchte zur Sicherheit noch eine CRC hinzufügen.
Das Problem ist, dass die Berechnung der CRC ohne den Speicherbereich 
für die CRC durchführen will/muss.
Der erste Ansatz mit
1
typedef struct
2
{
3
  uint8_t param_1;
4
  uint16_t param_2;
5
  uint8_t param_3[9];
6
  uint16_t crc;
7
} conf_t
8
conf_t config;
9
get_default_config(&config);
10
uint8_t crc_size = sizeof(config) - sizeof(config.crc);
11
config.crc = calc_crc(&config, crc_size);
scheiterte, da auch am Ende Padding-Bytes eingefügt wurden.
Die zweite Lösung empfinde ich als unsauber, funktioniert aber erstmal.
1
uint8_t crc_size = (uint8_t)(&(config.crc)) - (uint8_t)&config;
aktuell habe ich die Idee, die Struktur so aufzubauen:
1
typedef struct
2
{
3
  uint8_t param_1;
4
  uint16_t param_2;
5
  uint8_t param_3[9];
6
} conf_t;
7
typedef struct
8
{
9
  config_t conf;
10
  uint16_t crc;
11
} conf_rcr_t;
Habt ihr eine bessere und vor allem sauberere Lösung?

Simon

: Bearbeitet durch User
von N. M. (mani)


Lesenswert?

1
typedef struct
2
{
3
  uint8_t param_1;
4
  uint16_t param_2;
5
  uint8_t param_3[9];
6
  uint16_t crc;
7
} conf_t;
8
9
printf("%d\n", sizeof(conf_t)); //16


Etwas nachdenken beim anordnen der Parameter:
1
typedef struct
2
{
3
  uint16_t param_2;
4
  uint8_t param_3[9];
5
  uint8_t param_1;
6
  uint16_t crc;
7
} conf_t;
8
9
printf("%d\n", sizeof(conf_t)); //14

Alternativ:
1
typedef struct __attribute__((packed))
2
{
3
  uint8_t param_1;
4
  uint16_t param_2;
5
  uint8_t param_3[9];
6
  uint16_t crc;
7
} conf_t;
8
printf("%d\n", sizeof(conf_t)); //14

Simon G. schrieb:
> Das Problem ist, dass die Berechnung der CRC ohne den Speicherbereich
> für die CRC durchführen will/muss.

Wieso das? Rechne doch über die komplette struct (mit CRC) und 
vergleiche mit 0x0000/0xFFFF (je nach final)

Simon G. schrieb:
> aktuell habe ich die Idee, die Struktur so aufzubauen:

Und was macht das besser?
1
printf("%d\n", sizeof(conf_rcr_t)); //16

Dann kannst du auch gleich mit offsetof(CRC) arbeiten.

: Bearbeitet durch User
von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

Simon G. schrieb:
> uint8_t crc_size = (uint8_t)(&(config.crc)) - (uint8_t)&config;
1
 uint8_t crc_size = offsetof(conf_t, crc);

Edit: da war mani schneller :-)

: Bearbeitet durch User
von Simon G. (sigro)


Lesenswert?

N. M. schrieb:
> Etwas nachdenken beim anordnen der Parameter:
>
1
> typedef struct __attribute__((packed))
2
>

Moin und vielen Dank,
stimmt, packed wäre auch noch eine gute alternative.
> Wieso das? Rechne doch über die komplette struct (mit CRC) und
> vergleiche mit 0x0000/0xFFFF (je nach final)
Das verstehe ich leider noch nicht ganz. Ich möchte ja die gespeicherte 
Konfiguration mit der gespeicherten CRC überprüfen, um Fehler beim 
Speichern oder Lesen zu erkennen.

N. M. schrieb:
> Und was macht das besser?printf("%d\n", sizeof(conf_rcr_t)); //16
>
> Dann kannst du auch gleich mit offsetof(CRC) arbeiten.

Perfekt, das gefällt mir und war irgendwie nicht auf meinem Schirm.

von Simon G. (sigro)


Lesenswert?

N. M. schrieb:
> Simon G. schrieb:
>> aktuell habe ich die Idee, die Struktur so aufzubauen:
>
> Und was macht das besser?

da hätte ich dann
1
conf_crc_t conf;
2
uint_t crc_size = sizeof(conf.conf);
genommen.

von N. M. (mani)


Lesenswert?

Christopher B. schrieb:
> Edit: da war mani schneller :-)

Ja, ich hab noch editiert und offsetof hinzugefügt.

Simon G. schrieb:
> Das verstehe ich leider noch nicht ganz. Ich möchte ja die gespeicherte
> Konfiguration mit der gespeicherten CRC überprüfen, um Fehler beim
> Speichern oder Lesen zu erkennen.

Na du hast doch irgendwann Daten die du speichern möchtest. Zu den Daten 
berechnest du die CRC und speicherst diese konsistent mit den Daten im 
Flash.
Irgendwann liest du die Daten wieder aus und willst sie validieren. Wenn 
du nun über die komplette struct (mit CRC) die CRC rechnest muss doch 0 
rauskommen.

von N. M. (mani)


Lesenswert?

Simon G. schrieb:
> da hätte ich dann
>
> conf_crc_t conf;
>
> uint_t crc_size = sizeof(conf.conf);
>
> genommen.

conf_t ist doch das Problem. Genauer gesagt weil du auf das erste 
uint8_t versuchst ein uin16_t zu platzieren. Aufgrund der ungeraden 
Adresse macht der Compiler das aber nicht und fügt ein padding Byte ein. 
Später beim Übergang vom Array auf uint16_t das gleiche nochmal.
Also musst du doch das Vermeiden.
Das bekommst du mit der gezeigten Variante ja aber nicht hin.
Also hast du wieder 2 Byte zu viel...

von Simon G. (sigro)


Lesenswert?

N. M. schrieb:
> Also musst du doch das Vermeiden.
> Das bekommst du mit der gezeigten Variante ja aber nicht hin.
> Also hast du wieder 2 Byte zu viel...

Die Padding-Bytes sind nicht unbedingt das Problem, da sie ja bei der 
CRC Berechnung berücksichtigt werden.
Nur die Padding-Bytes am Ende der Struktur zusammen mit meiner 
fehlerhaften Berechnung des Offsets führten dazu, dass die CRC in die 
CRC Berechnung einfloss und damit eine andere CRC berechnet wurde als 
abgespeichert.

von Simon G. (sigro)


Lesenswert?

N. M. schrieb:
> Christopher B. schrieb:
> Irgendwann liest du die Daten wieder aus und willst sie validieren. Wenn
> du nun über die komplette struct (mit CRC) die CRC rechnest muss doch 0
> rauskommen.
Wie ich das am Besten nutzen kann, muss ich mir noch überlegen.

von Bauform B. (bauformb)


Lesenswert?

Kann man sich auf Padding-Bytes verlassen? Die Anzahl ist wohl immerhin 
implementation defined, aber der Inhalt könnte random sein. _

__attribute__((packed)) finde ich auch unsauber. Und ich fände es 
übersichtlicher, wenn crc ganz am Anfang stände.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.