struct einer Funktion übergeben

Gast #7341719
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
}
#7341729
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.

Gast #7341731
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
}
Gast #7341737
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.

Gast #7341746
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.

#7341747
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.

Gast #7341752
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.

Gast #7341794
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?

Gast #7341796
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));
#7341805
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ß

#7341899
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.

#7341970
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.

Gast #7341976
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
}
Gast #7342126
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 im Beitrag #7341737:

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.

#7342129
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.

Gast #7342142
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);
#7342148
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.

Gast #7342169
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)
Gast #7342476
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);
Gast #7342497
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)?
Gast #7342649
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.

Gast #7343002
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren