Forum: Mikrocontroller und Digitale Elektronik struct einer Funktion übergeben


von Coder (Gast)


Lesenswert?

Guten Morgen,

wie kann ich eine Struktur einer Funktion übergebe?
Ziel soll es sein, dass die Funktion WriteToMemory jetzt nicht drei
Parameter für jede einzelne Struktur bekommt. Wie könnte dies mit einem 
Übergabeparameter realisiert werden?
1
typedef struct
2
{
3
  uint8_t value1,
4
  uint32_t value2,
5
  bool value3
6
}st_data1;
7
8
typedef struct
9
{
10
  uint8_t value1,
11
  uint32_t value2
12
}st_data2;
13
14
typedef struct
15
{
16
  uint8_t value1,
17
  uint32_t value2,
18
  uint8_t key[16]
19
}st_data3;
20
21
void WriteToMemory(...)
22
{
23
24
}

von Rolf M. (rmagnus)


Lesenswert?

Coder schrieb:
> wie kann ich eine Struktur einer Funktion übergebe?

Genau wie andere Typen auch, per Kopie oder per Zeiger.

> Ziel soll es sein, dass die Funktion WriteToMemory jetzt nicht drei
> Parameter für jede einzelne Struktur bekommt. Wie könnte dies mit einem
> Übergabeparameter realisiert werden?

Das heißt, die Funktion soll alle drei Strukturen auf einmal bekommen, 
aber nur mit einem Parameter? Dann kannst du diese einfach in einer 
übergeordneten Struktur zusammenfassen.

: Bearbeitet durch User
von fop (Gast)


Lesenswert?

Na mit einer Struct :-)

Structs können auch Mitglieder einer Struct sein.
1
typedef struct
2
{
3
  st_data1 eins;
4
  st_data2 zwei;
5
  st_data3 drei;
6
} s42_t;
7
8
void WriteToMemory(s42_t alles)
9
{
10
}

von Coder (Gast)


Lesenswert?

Je nach Situation soll die entsprechende Struktur der Funktion übergeben 
werden. Zusammenfassen kann ich leider nicht machen.
Die Daten von der Struktur st_data1 soll nur während Produktion in das 
Flash geschrieben werden. Bei den anderen Strukturen entweder permanent 
oder ab und zu.

von Coder (Gast)


Lesenswert?

Muss ich die drei Strukturen zusammenfassen?

von HildeK (Gast)


Lesenswert?

Deinem 'WriteToMemory' musst du eben noch mit einem weiteren Parameter 
mitteilen, welcher Teil vom Vorschlag von 'fop' geschrieben werden soll.

Andernfalls brauchst du drei unterschiedliche WriteToMemory-Funktionen, 
die du entsprechend aufrufst, weil die drei Structs ja unterschiedlich 
sind und du in der Funktion wissen musst, welche Parameter im Struct wie 
belegt sind.

Es mag noch Tricks geben, die mir aber nicht bekannt sind.

von Rolf M. (rmagnus)


Lesenswert?

Es ist nicht so ganz klar, was du eigentlich genau willst. Wie sollen 
die Daten geschrieben werden? Als Binärklumpen oder serialisiert? Wohin? 
Woran willst du nachher beim lesen erkennen, welche der Strukturen da 
drin steht?
Die einfachste Art einer Schreibfunktion wäre eine, die einen void* und 
eine Größe als Parameter bekommt. Da kannst du schreiben, was du willst.

von Coder (Gast)


Lesenswert?

Die jeweiligen Daten von den Strukturen soll in ein internes Flash vom 
Mikrocontroller byteweise abgelegt werden.

Das mit einem void* als Übergabeparameter wäre eine gute Möglichkeit. 
Allerdings brauche ich da natürlich noch die Längenangabe. Dies kann ich 
mit sizeof(..) herausfinden.

von Simon (Gast)


Lesenswert?

ich glaube, er möchte immer die übergebene Struktur gespeichert werden 
soll.
da würde ich einen Cast auf einen Pointer auf uint8_t und die Länge der 
Struktur als Parameter vorsehen.

von Coder (Gast)


Lesenswert?

Danke für die Untersützung. Wie würde dies als Beispiel aussehen?

von Simon (Gast)


Lesenswert?

Coder schrieb:
> Danke für die Untersützung. Wie würde dies als Beispiel aussehen?

Wie würdest du eine Funktion schreiben, die als Parameter einen Pointer 
auf einen uint8_t-Typ und eine Größenangabe erwartet?
Wie ermittelst du die Adresse einer Struktur?
Wie castest du Typen?

von Coder (Gast)


Lesenswert?

1
st_data1 data1;
2
st_data2 data2;
3
st_data3 data3;
4
5
WriteToMemory((uint8_t *)&data1, sizeof(data1));
6
WriteToMemory((uint8_t *)&data2, sizeof(data2));
7
WriteToMemory((uint8_t *)&data3, sizeof(data3));

von Aabeku K. (aabeku)


Lesenswert?

Iwie fehlen mir Informationen um das zu beantworten?!?

Also ich fasse mal zusammen. Du kannst die 3 Structs nicht kombinieren, 
weil das 1. Struct konstante Werte beinhaltet. Du kannst aber auch 
Struct-Member konstant deklarieren. (siehe https://matt.sh/sytycc)

Dann möchtest du das Struct in einen Speicher schreiben. Was für ein 
Speicher das ist, ist erstmal egal. Was wichtig für mich zu wissen wäre, 
welche Wortbreite hat der Speicher (ich gehe jetzt mal von 8Bit=1Byte 
aus).

Wenn du nun das struct speichern willst, dann kannst du das indem du das 
struct in den Type uint8_t umcastest (hat schon ein Vorredner 
geschrieben). Das machst du so:
1
typedef struct{
2
   const int a; //can only be set in initialization
3
   int b; //can be read and written
4
}new_type;
5
6
void write_to_memory(uint8_t* ptr, unsigned int len){
7
   ...
8
}
9
10
int main(void){
11
   ...
12
   new_type data_a = {5, 2};
13
   uint8_t* pointer_to_struct = (uint8_t*) &data_a; //cast pointer to struct into uint8_t*
14
   unsigned int struct_len = sizeof(data_a);
15
   write_to_memory(pointer_to_struct, struct_len);
16
}

Die Länge deines Structs ist immer gleich. Es sei denn du hast 
dynamische Arrays in deinem Struct(wenn das geht, ich glaube aber 
schon). Dann musst du natürlcih wissen wie lang dein Struct war beim 
abspeichern und die Daten auch genau zuordnen können.

Wenn du ein statisches Struct hast, dann kann es sein dass dein Compiler 
Paddings um die einzelnen Variablen hinzufügt. Das sind einfach leere 
Bytes um z.B. eine 8Bit Variable auf die 32Bit Wortlänge des Controllers 
zu bringen oder sowas. Die sind aber auch immer gleich (bei statischen 
Structs).

Das heißt, wenn du ein Struct in den Speicher schreibst und wieder 
ausließt, dann kannst due die gelesenen Daten einfach deinem Struct 
zuweisen und deine Variablen sollten die richtigen Werte haben.

Wichtig ist heir auch die Reihenfolge. Wenn du die Bytes falsch herum 
deinem Struct zuweist, kommt natürlich kauderwelsch raus.

Hoffe es hilft weiter.

Gruß

: Bearbeitet durch User
von Coder (Gast)


Lesenswert?

Ok Danke vielmals.

von Markus F. (mfro)


Lesenswert?

Tja, Du wolltest zwar "nur" schreiben, aber spätestens beim 
Wiederauslesen der Daten wirst Du das Problem haben, dass Du an der 
Stelle nicht (mehr) weisst, was Du da eigentlich hingeschrieben hast 
(liest Du nun ein st_data1, ein st_data2 oder ein st_data_3?).

Also solltest Du (zumindest) diese Info noch irgendwo hinterlegen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

HildeK schrieb:
> Es mag noch Tricks geben, die mir aber nicht bekannt sind.

Es gibt noch die Möglichkeit dies per varargs-Funktion zu machen.

Das nur der Vollständigkeit halber; es soll keine Anregung sein, sowas 
hier zu verwenden.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

eine Funktion für verschiedene Strukturen geht sowieso nicht. Wird bspw. 
key in der Funktion verwendet gibt es Mecker wenn eine Struktur ohne key 
übergeben wird.

Ich würde mich auf eine! Struktur für alle einigen, dass erleichtert 
vieles. Man muss die Member woanders ja nicht verwenden wenn nicht 
benötigt.
1
struct Daten
2
{
3
  uint8_t value1;
4
  uint32_t value2;
5
  bool value3;
6
  uint8_t key[16];
7
};
8
9
Daten st_data1;
10
Daten st_data2;
11
Daten st_data3;
12
13
void writeToMemory(Daten &data)
14
{
15
  ... data.value1 ...
16
  ... data.value2 ...
17
  ... data.value3 ...
18
19
  for(auto &i : data.key)
20
  {
21
    ... i ...
22
  } 
23
}
24
25
...
26
writeToMemory(st_data1);
27
writeToMemory(st_data2);
28
writeToMemory(st_data3);
29
...

Ansonsten vielleicht mit union.

von foo (Gast)


Lesenswert?

1
#include <stdint.h>
2
#include <stdlib.h>
3
#include <stdio.h>
4
5
typedef struct {
6
  uint8_t value1;
7
  uint32_t value2;
8
  int value3;
9
} st_data1;
10
11
typedef struct
12
{
13
  uint8_t value1;
14
  uint32_t value2;
15
} st_data2;
16
17
typedef struct {
18
  uint8_t key_size;
19
  uint32_t value2;
20
  uint8_t key[16];
21
} st_data3;
22
23
typedef struct {
24
  st_data1 D1;
25
  st_data2 D2;
26
  st_data3 D3;
27
} TheSuperStruct;
28
29
const st_data1 x = {233, 12345, 999};
30
const st_data2 y = {44, 990034};
31
const st_data3 z = {
32
  16, 5675,
33
  {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
34
};
35
36
TheSuperStruct super = {x, y, z};
37
38
void WriteToMemory(TheSuperStruct *s) {
39
  printf("\nst1-values: %i,%i,%i\n", s->D1.value1, s->D1.value2, s->D1.value3);
40
  printf("st2-values: %i,%i\n", s->D2.value1, s->D2.value2);
41
  printf("\nwriting data:");
42
  for (int i = 0; i < s->D3.key_size; i++) {
43
    printf("\nwriting param: %i", s->D3.key[i]);
44
  }
45
  printf("\nfinished with st3 config: %i\n", s->D3.value2);
46
  printf("............................................\n");
47
  printf("Writing Mem done, Thank You for using mem writer!");
48
  return;
49
}
50
51
int main(int argc, char *argv[]) {
52
  WriteToMemory(&super);
53
  printf("\nDONE\n");
54
  return EXIT_SUCCESS;
55
}

von HildeK (Gast)


Lesenswert?

Johann L. schrieb:
> Es gibt noch die Möglichkeit dies per varargs-Funktion zu machen.

Ja, vielen Dank. Das war es wohl, ich hatte an die Parameterübergabe von 
printf gedacht, dort wird es auch mit varargs gemacht (soweit ich mich 
erinnere).
Das ist nichts, was ich in meinen Funktionen verwende ... 😀

Eine andere, vielleicht funktionierende Möglichkeit könnte ein union aus 
den drei structs sein. Ähnlich wie foo es mit dem Superstruct vorhat.
Könnte gehen, weil die beiden ersten Variablen gleichen Datentyps sind. 
Trotzdem muss zur Unterscheidung welcher struct übergeben wurde noch 
eine Information hinzugefügt werden.

Egal wie, einer WriteToMemory-Funktion muss das hier klar gemacht 
werden:
Coder schrieb:
> Die Daten von der Struktur st_data1 soll nur während Produktion in das
> Flash geschrieben werden. Bei den anderen Strukturen entweder permanent
> oder ab und zu.

von Wilhelm M. (wimalopaan)


Lesenswert?

HildeK schrieb:
> Eine andere, vielleicht funktionierende Möglichkeit könnte ein union aus
> den drei structs sein.

Das ist totaler Bruch: Polymorphie-für-Arme.

Da man in C nun mal Funktionen nicht überladen kann, schreibt man 3 
Funktionen mit unterschiedlichen Namen zum Serialisieren. Intern rufen 
die dann eine vierte auf, die eine byte-weise Serialisierung durchführt.

Wenn das Zeugs an unterscheidlichen Stellen im Flash/EEprom liegt, ist 
das Deserialisieren ja auch keine Thema. Andernfalls benötigt man ein 
Typ-Marker.

von foobar (Gast)


Lesenswert?

Während die Vorschläge hier immer abstruser werden, benutzt der Rest der 
Welt schon sein Jahrzehnten:
1
void write_ee_block(unsigned eeaddr, const void *data, size_t len)
2
{
3
    // z.B.:
4
    const char *src = data;
5
    while (len--)
6
        write_ee_char(eeaddr++, *src++);
7
}
8
    ...
9
    st_data1 data1;
10
    st_data2 data2;
11
    st_data3 data3;
12
    ...
13
    write_ee_block(0x00, &data1, sizeof data1);
14
    write_ee_block(0x20, &data2, sizeof data2);
15
    write_ee_block(0x40, &data3, sizeof data3);

von Wilhelm M. (wimalopaan)


Lesenswert?

foobar schrieb:
> Während die Vorschläge hier immer abstruser werden, benutzt der Rest der
> Welt schon sein Jahrzehnten:

Genau so hatte ich es beschrieben, allerdings mit 3 convenience-wrappern 
darum:

Wilhelm M. schrieb:
> Da man in C nun mal Funktionen nicht überladen kann, schreibt man 3
> Funktionen mit unterschiedlichen Namen zum Serialisieren. Intern rufen
> die dann eine vierte auf, die eine byte-weise Serialisierung durchführt.

von A. S. (Gast)


Lesenswert?

Coder schrieb:
> Ziel soll es sein, dass die Funktion WriteToMemory jetzt nicht drei
> Parameter für jede einzelne Struktur bekommt.

Wenn Du mit "3" Adresse, Zeiger und Länge meinst:
1
struct Tmem {
2
   uint32_t addr;
3
   void     *ptr;
4
   int      len;
5
};
6
7
st_data2 d2;
8
St_data3 d3;
9
10
struct Tmem m2 = {423, &d2, sizeof d2);
11
12
void WriteToMemory(struct Tmem mem)
13
{
14
}
15
WriteToMemory(m2)

von Coder (Gast)


Lesenswert?

Hi, das mit dem letzten Beispiel sieht sehr interessant aus. Werde es 
mal morgen testen.

von Coder (Gast)


Lesenswert?

Ich habes mal so umgesetzt wie oben bereits gezeigt wird.
1
typedef struct{
2
3
   const int a; //can only be set in initialization
4
5
   int b; //can be read and written
6
7
}new_type;
8
9
void write_to_memory(uint8_t* ptr, unsigned int len){
10
11
   ...
12
13
}
14
15
int main(void){
16
17
   ...
18
19
   new_type data_a = {5, 2};
20
21
   uint8_t* pointer_to_struct = (uint8_t*) &data_a; //cast pointer to struct into uint8_t*
22
23
   unsigned int struct_len = sizeof(data_a);
24
25
   write_to_memory(pointer_to_struct, struct_len);
26
27
}
1
Das Auslesen würde dann so aussehen:
2
3
read_from_memory(pointer_to_struct, struct_len);

von Rolf M. (rmagnus)


Lesenswert?

Coder schrieb:
> uint8_t* pointer_to_struct = (uint8_t*) &data_a; //cast pointer to
> struct into uint8_t*

Warum eigentlich uint8_t*? Nimm einfach einen void*. Der ist dafür da 
und macht den Cast unnötig.

>    unsigned int struct_len = sizeof(data_a);

Für Objektgrößen sollte man size_t bevorzugen.

von A. S. (Gast)


Lesenswert?

Coder schrieb:
> Ich habes mal so umgesetzt wie oben bereits gezeigt wird.

 * Wo wird die zugehörige EEPROM-Adresse angegeben?
 * was denkst Du bewirkt const bei "a" in der Struktur?
 * welchen Sinn haben pointer_to_struct und struct_len (statt direkt 
&data_a und sizeof data_a)?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Coder schrieb:
> void write_to_memory(uint8_t* ptr, unsigned int len){

Korrekter Prototyp wäre
1
void write_to_memory (const uint8_t* ptr, size_t len)

von Rolf M. (rmagnus)


Lesenswert?

Rolf M. schrieb:
> Warum eigentlich uint8_t*? Nimm einfach einen void*.

Ich würde das dann so schreiben:
1
    void write_to_memory(const void* ptr, size_t len)
und
1
    write_to_memory(&data_a, sizeof data_a);

: Bearbeitet durch User
von Coder (Gast)


Lesenswert?

Guten Morgen,

ich Funktion braucht keine Adresse. Es handelt sich um eine spezielle 
Lib die den non volatile memory managed. Ich brauche aber noch einen 
weiteren Parameter der die Nummer des Objekte übergeben soll.

von A. S. (Gast)


Lesenswert?

Coder schrieb:
> ich Funktion braucht keine Adresse. Es handelt sich um eine spezielle
> Lib die den non volatile memory managed. Ich brauche aber noch einen
> weiteren Parameter der die Nummer des Objekte übergeben soll.

schreib einfach was Du hast, was Du brauchst und wie Du es Dir 
vorstellst. Wir kennen weder Deine Lib noch Deine Objekte oder Deine 
Vorstellungen.

von 49673 (Gast)


Lesenswert?

C++ und templates?

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.