Forum: Compiler & IDEs Multi-dimensionale Arrays mit unterschiedlichen Größen in C


von DerBayer (Gast)


Lesenswert?

Hallo!

Ich würde gerne in C eine Abfolge von Befehlen für einen Betriebsmodus 
in einem Array zusammenfassen. Das Problem: Die Anzahl von und die Länge 
der einzelnen Befehlen variiert von Betriebsmodus zu Betriebsmodus.

Pseudocode, mit <n=?> für Anzahl die Anzahl der Bytes eines Befehls 
(BSP.: {0xDE, 0xAD, 0xBE, 0xEF} => {<n=4>}):
1
const uint8_t Steuerung_Befehl_AutomatikBetrieb[][] = {{<n=3>}, {<n=18>}, {<n=10>}};
2
const uint8_t Steuerung_Befehl_Betriebszustand_CROW[][] = {{<n=5>}, {<n=10>}, {<n=10>}{<n=16>}, {<n=21>}, {<n=28>}};
3
...

Wie bekomme ich das am Besten gelöst?

Danke und Grüße aus Bayern
Finn

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

DerBayer schrieb:
> Das Problem: Die Anzahl von und die Länge der einzelnen Befehlen
> variiert von Betriebsmodus zu Betriebsmodus.
Aber es gibt eine vordefinierte Maximalgröße?
Oder ist das Alles volldynamisch?

> Wie bekomme ich das am Besten gelöst?
Das geht am ehesten in Richtung "Union".
Damit wird über einen bestimmten Speicherbereich einfach eine "Maske" 
gelegt und der jeweilige Speicherinhalt einfach unterschiedlich 
interpretiert.

> Wie bekomme ich das am Besten gelöst?
Verhindere durch eine "geschickte" Befehlsstruktur das eigentliche 
Problem:
> Die Anzahl von und die Länge der einzelnen Befehlen
> variiert von Betriebsmodus zu Betriebsmodus.

: Bearbeitet durch Moderator
von DerBayer (Gast)


Lesenswert?

Lothar M. schrieb:
> Aber es gibt eine vordefinierte Maximalgröße?
> Oder ist das Alles volldynamisch?

Maximalgröße? - Ja, sicherlich: 240 Bytes. Dennoch würde ich es mehr als 
volldynamisch bezeichnen.

Lothar M. schrieb:
> Das geht am ehesten in Richtung "Union".
> Damit wird über einen bestimmten Speicherbereich einfach eine "Maske"
> gelegt und der jeweilige Speicherinhalt einfach unterschiedlich
> interpretiert.

Da alles Variable ist hilft mir das nicht weiter. Und bei einer Union 
müsste ich auch auf irgendeine "Maske" zugreifen. Das heißt ich muss im 
Programmcode wissen was kommt ...

Lothar M. schrieb:
> Verhindere durch eine "geschickte" Befehlsstruktur das eigentliche
> Problem:
>> Die Anzahl von und die Länge der einzelnen Befehlen
>> variiert von Betriebsmodus zu Betriebsmodus.

Tja ... Das kann ich nicht ändern! Das "System" mit dem ich kommuniziere 
kommt ja nicht von mir bzw. "uns".

...

Mir ist nur ein Umweg über eine Struktur eingefallen. Das ganze kostet 
aber dann je Befehl 5 Byte mehr Speicher. Unschön!
1
#define MAKE_CMD_ENTRY(cmd)     { sizeof(cmd), cmd }
2
3
typedef struct
4
{
5
  const uint8_t  size;
6
  sonst uint8_t* cmd;
7
} CMD;
8
9
const uint8_t Steuerung_Befehl_A[] = {<n=3>};
10
const uint8_t Steuerung_Befehl_B[] = {<n=18>};
11
const uint8_t Steuerung_Befehl_C[] = {<n=10>};
12
13
const CMD Steuerung_Befehl_AutomatikBetrieb[] = { MAKE_CMD_ENTRY(Steuerung_Befehl_A), 
14
                                                    MAKE_CMD_ENTRY(Steuerung_Befehl_B), 
15
                                                    MAKE_CMD_ENTRY(Steuerung_Befehl_C) };

Gruß
Finn

von Stromverdichter (Gast)


Lesenswert?

DerBayer schrieb:
> Die Anzahl von und die Länge
> der einzelnen Befehlen variiert von Betriebsmodus zu Betriebsmodus.

Ich denke, du solltest dir mal das Thema "verkettete Listen" anschauen. 
vielleicht trifft das eher deinen Anwendungsfall

von 53453453454353 (Gast)


Lesenswert?

vlt ein struct anlegen mit größe und pointer für den einzelnen befehl

wenn sich die befehle wiederholen eine einzelne liste anlegen mit den 
befehlen.
1
const uint8_t cmd1[]={..};
2
const uint8_t cmd2[]={.....};
3
...
4
5
typedef struct{
6
   const uint8_t len;
7
   const uint8_t *cmd;
8
}xxx_t
9
10
// modi 1
11
const xxx_t Steuerung_Befehl_AutomatikBetrieb[]={
12
 { 2 , cmd1},
13
 { 5 , cmd2},
14
 { 5 , cmd2}
15
}
16
17
// modi 2
18
const xxx_t Steuerung_Befehl_Betriebszustand_CROW[]={
19
 { 5 , cmd2},
20
 { 2 , cmd1},
21
 { 2 , cmd1}
22
}

von Eric B. (beric)


Lesenswert?

DerBayer schrieb:

> Da alles Variable ist hilft mir das nicht weiter.

So variabel ist es anscheint nicht, wenn du alle zu sendene Befehle im 
Flash legen kannst.

> Das heißt ich muss im
> Programmcode wissen was kommt ...

Du musst do sowieso wissen "was kommt", sonst würdest du nicht wissen 
welches Befehl zu senden ist?

> Tja ... Das kann ich nicht ändern! Das "System" mit dem ich kommuniziere
> kommt ja nicht von mir bzw. "uns".

Also:
- Wieviele von diesen Befehlen gibt es?
- Sind die zur Laufzeit konstant, oder enthalten sie variabele Teile?

> Mir ist nur ein Umweg über eine Struktur eingefallen. Das ganze kostet
> aber dann je Befehl 5 Byte mehr Speicher. Unschön!

? Nöh, doch nur 1 oder 2 bytes, je nachdem wie lange ein so ein Befehl 
sein kann.
1
// 1st element is length, rest is data
2
uint8_t cmd1[] = { 3, 0xF0, 0x0B, 0xAA };
3
uint8_t cmd2[] = { 245, 0x00, ... };
4
uint8_t cmd3[] = { 1, 0x02 };
5
6
void send(uint8_t cmd)
7
{
8
  for (uint8_t i = 1; i <= cmd[0]; i++)
9
    send_byte(cmd[i]);
10
}
11
12
...
13
    if(need_to_send_cmd1)
14
        send(cmd1);
15
    else
16
        send(cmd2);
17
...

EDIT: nur aufpassen wenn der Befehl 256 bytes lang ist :-)

: Bearbeitet durch User
von DerBayer (Gast)


Lesenswert?

@53453453454353:

Ähm ... Ist das nicht meine Lösung!?

Stromverdichter schrieb:
> Ich denke, du solltest dir mal das Thema "verkettete Listen" anschauen.
> vielleicht trifft das eher deinen Anwendungsfall

Glaube ich nicht. Wären dann sogar 9 Bytes, statt 5, da ich einen 
zusätzlichen Pointer sichern müsste:
1
typedef struct
2
{
3
  const uint8_t  size;
4
  const uint8_t* cmd;
5
  const CMD*     next;
6
} CMD;

Last but not least, sind verkettete Listen nur bei dynamischer 
Speicherallokierung von Nutzen. Nicht bei statischer ...

von 53453453454353 (Gast)


Lesenswert?

DerBayer schrieb:
> Ähm ... Ist das nicht meine Lösung!?

quasi gleiche idee ^^
das forum ist manchmal nicht so schnell in der aktualisierung.
als ich geschrieben hatte war dein post nioch nicht da

von Peter D. (peda)


Lesenswert?

Ich benutze ein Pointer-Array (2 Byte mehr je Eintrag).
1
char *cmd_str[] = { "Set", "Get", "Calib", "Info", "Uptime", "Reset", "Eestore", "" };

von DerBayer (Gast)


Lesenswert?

Eric B. schrieb:
> So variabel ist es anscheint nicht, wenn du alle zu sendene Befehle im
> Flash legen kannst.

Ja richtig. Die sind fest, ohne variablen Inhalt zur Laufzeit.

Eric B. schrieb:
> if(need_to_send_cmd1)
>         send(cmd1);
>     else
>         send(cmd2);

Ein aufeinanderfolgendes explizites Senden von Kommandos a la
1
send(cmd1);
2
send(cmd2);
will ich ja eben vermeiden.


Eric B. schrieb:
> EDIT: nur aufpassen wenn der Befehl 256 bytes lang ist :-)

Gibt es ja eben bei 8 Bit nicht ;-)

Peter D. schrieb:
>
1
char *cmd_str[] = { "Set", "Get", "Calib", "Info", "Uptime", "Reset", "Eestore", "" };

Lustig, dass das so funktioniert und mit einem Byte-Array nicht, obwohl 
es prinzipiell das selbe ist, denn "Set" ist ja ein Byte-Array 
{'S','e','t', 0}.

Dennoch geht das nicht:
1
const uint8_t* Steuerung_Befehl_AutomatikBetrieb[][] = {{<n=3>}, {<n=18>}, {<n=10>}};

von MaWin (Gast)


Lesenswert?

Wie wäre es mit einem 1-Dim Array, wo alles hintereinander steht. Und 
ein zweites Array mit jeweils dem Anfangsindex des datensatzes im ersten 
Array.

von Eric B. (beric)


Lesenswert?

DerBayer schrieb:

> Eric B. schrieb:
>> EDIT: nur aufpassen wenn der Befehl 256 bytes lang ist :-)
>
> Gibt es ja eben bei 8 Bit nicht ;-)

Könnte man aber mit 0 kodieren.

>
> Peter D. schrieb:
>>
1
char *cmd_str[] = { "Set", "Get", "Calib", "Info", "Uptime", "Reset", 
2
> "Eestore", "" };
>
> Lustig, dass das so funktioniert und mit einem Byte-Array nicht, obwohl
> es prinzipiell das selbe ist, denn "Set" ist ja ein Byte-Array
> {'S','e','t', 0}.

cmd_str ist dan auch ein Array mit Pointern zu den Verschiedenen 
Texten.
Wäre also äquivalent zu
1
uint8_t cmd1 = { 'S', 'e', 't', 0 };
2
uint8_t cmd2 = { 'G', 'e', 't', 0 };
3
uint8_t cmd3 = { 'C', 'a', 'l', 'i', 'b', 0 };
4
5
uint8_t *cmds[] = { cmd1, cmd2, cmd3 ... };

: Bearbeitet durch User
von Eric B. (beric)


Lesenswert?

DerBayer schrieb:
> Ein aufeinanderfolgendes explizites Senden von Kommandos a la
>  send(cmd1);
>  send(cmd2);
> will ich ja eben vermeiden.

Wieso, weshalb und wozu? Irgendwann wirst du doch entscheiden müssen ob 
du cmd1 oder cmd2 schicken willst. Und wenn du mehrere cmd-s in Reihe 
schicken möchtest, dann eben so:
1
uint8_t *cmd_sequence1[] = { cmd1, cmd2, cmd3, 0 };
2
uint8_t *cmd_sequence_pi[] = { cmd3, cmd1, cmd4, cmd1, cmd5, 0};

oder über eine vararg-Funktion a la printf:
1
void send_cmds(uint8_t n, ...)
2
{
3
  va_list argp;
4
  va_start(n, argp);
5
  for(uint8_t i=0; i < n; i++)
6
    send(va_arg(argp, (uint8_t *)));
7
  va_end(argp);
8
}
9
10
...
11
send_cmds(3, cmd1, cmd2, cmd3);
12
send_cmds(5, cmd3, cmd1, cmd4, cmd1, cmd5);

von Achim (Gast)


Lesenswert?

Du kannst 0-terminierte Listen auch mit einem weiteren Sonderzeichen 
hierarchisch aufbauen. Beispiel: alle Befehle als Strings mit 0 
hintereinander, Ende ist wenn ein String mit 1 anfängt oder aufhört.
Vorteil: einfache Nutzung von stringroutinen, minimalster Overhead

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.