Forum: PC-Programmierung Flexible Array Member initialisieren in C


von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Nabend,

ich habe da eine Frage, wie initialisiert man einen flexiblen array 
member zur Compilezeit ohne einen Roman zu schreiben?

Beispiel:
1
typedef struct
2
{
3
    const unsigned Anzahl;
4
    uint8_t Werte[];
5
} Muster_t;
6
7
Muster_t MusterA = { 3, { 0, 0, 0 } };
8
Muster_t MusterB = { 1000, { ... } };

In einfachen Fällen wie bei MusterA geht das ja noch, aber wenns mal 
mehr wird wie bei MusterB...
Achja, natürlich könnte ich auch den Speicher per malloc reservieren, 
nullen (bzw. calloc) und die Werte darauf umbiegen, aber das sollte doch 
irgendwie einfacher gehen.
Oder muss ich wirklich ein Script basteln was mir z.B. 1000 Komma 
separierte Nullen als String baut?
Und ja, mir ist schon klar, dass das statische Initialisieren von 
flexiblen array membern eigentlich nicht funktionieren sollte, aber der 
gcc macht da eh eine Ausnahme indem er den flexiblen member zu einem 
statischen macht mit der Größe der Anzahl der Initialisierungswerte.
Was dann natürlich auch eine Möglichkeit wäre, indem man selber für jede 
benötigte Größe des array member ein struct mit dem passenden statischen 
array baut; mit dem Ergebnis, dass man dann eventuell einen ganzen Zoo 
an structs hat.
Oder gibt es da noch eine andere Möglichkeit?

Ok, eine Möglichkeit wäre eventuell das Struct und das Array separat 
anzulegen und nur drauf zu pointern:
1
typedef struct
2
{
3
    const unsigned Anzahl;
4
    uint8_t *Werte;
5
} Muster_t;
6
7
uint8_t MusterA_Werte[3] = { };
8
uint8_t MusterB_Werte[1000] = { };
9
10
Muster_t MusterA = { sizeof(MusterA_Werte), MusterA_Werte };
11
Muster_t MusterB = { sizeof(MusterB_Werte), MusterB_Werte };
Aber schöner wird das alles nicht.

: Bearbeitet durch User
Beitrag #7223532 wurde vom Autor gelöscht.
von michi (Gast)


Lesenswert?

Ein Skript, welches Dir Quellcode generiert? Oha, das klingt ziemlich 
abenteuerlich ;)

Was spricht denn dagegen, dass Du Dir eine Setup-Funktion schreibst, die 
das Array für Dich anhand der übergebenen Größe initialisiert?

Also statt
1
Muster_t MusterA = { 3, { 0, 0, 0 } };

zum Beispiel so:
1
Muster_t MusterA = setupMuster(3);

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

michi schrieb:
> Ein Skript, welches Dir Quellcode generiert? Oha, das klingt ziemlich
> abenteuerlich ;)

Noch nie eine diskrete Sinustabelle für die Verwendung in einem Array 
generiert oder ähnliches?

> Was spricht denn dagegen, dass Du Dir eine Setup-Funktion schreibst, die
> das Array für Dich anhand der übergebenen Größe initialisiert?
>
> Also statt
>
>
1
> Muster_t MusterA = { 3, { 0, 0, 0 } };
2
>
>
> zum Beispiel so:
>
>
1
> Muster_t MusterA = setupMuster(3);
2
>

Versuch doch einfach mal, nur so ungefähr, dir die Funktionsweise der 
setupMuster() Funktion zu überlegen...

von MaWin (Gast)


Lesenswert?

michi schrieb:
> Was spricht denn dagegen, dass Du Dir eine Setup-Funktion schreibst, die
> das Array für Dich anhand der übergebenen Größe initialisiert?

Dagegen spricht, dass du nicht weißt, was ein flexible array member ist.

von A. S. (Gast)


Lesenswert?

Schafft es der GCC, die Nullen wirklich zu Nullen oder kopiert er die?

Zudem ist es unschön, n manuell zu pflegen. Ich würde es separat machen.

Oder nur ein Array allokieren und die Struktur als Ptr darauf legen. Mit 
"init"Funktion, die den ptr zurückgibt,
1
 
2
3
4
5
Master_t *MasterPtrCreate(unsigned char *p, unsigned n)
6
{
7
Master_t *m = (Master_t *) p;
8
9
   m->Anzahl= n-sizeof m->Anzahl;
10
11
   return m;
12
13
}
14
...
15
16
void x(void)
17
{
18
static unsigned char buf[1234];
19
20
   Master_t *m=MasterPtrCreate(buf, sizeof buf);
21
   ...
22
}

von ein lupenreiner Demokrat (Gast)


Lesenswert?

Tim T. schrieb:
> Achja, natürlich könnte ich auch den Speicher per malloc reservieren,
> nullen (bzw. calloc)

anders geht es auch nicht.

und die Länge des Arrays kann man in der Struktur erst ablegen, wenn der 
Speicher für die Struktur (und das Array) reserviert wurde. Somit muss 
man die Größe des Arrays vorher kennen.

von DPA (Gast)


Lesenswert?

ungetestet:
1
Muster_t x = { 1000, {[1000-1]=0} };

von ... (Gast)


Lesenswert?

> Somit muss man die Größe des Arrays vorher kennen.

"Dank" VLA ist das nicht mehr noetig.
Ich persoenlich wuerde das in Verbindung mit Controllern
aber nicht als Gewinn ansehen.

von ein lupenreiner Demokrat (Gast)


Lesenswert?

... schrieb:
> "Dank" VLA

haben nichts mit dem leeren Array am Strukturende zu tun und sind wieder 
abgeschafft.

von Wilhelm M. (wimalopaan)


Lesenswert?

Du kannst des mit designated-initializern initialisieren:
1
typedef struct {
2
    const unsigned Anzahl;
3
    uint8_t Werte[];
4
} Muster_t;
5
6
Muster_t MusterA = { 3, { 0} };
7
Muster_t MusterB = { 1000, {
8
                         [0] = 1,
9
                         [1] = 2,
10
                         [2] = 3,
11
                         [42] = 42
12
                     } 
13
                   };

Aber Achtung: hier gilt dann sizeof(Muster_t) == 2, was nicht der 
wirklichen Objektgröße entspricht.

von DPA (Gast)


Lesenswert?

Nö, c23 beschreibt immernoch überall, wie mit VLAs umzugehen ist. Sind 
also noch da.

von Wilhelm M. (wimalopaan)


Lesenswert?

DPA schrieb:
> Nö, c23 beschreibt immernoch überall, wie mit VLAs umzugehen ist. Sind
> also noch da.

Ich weiß nicht, auf was Du Dich beziehst. Aber was ich oben geschrieben 
habe, ist kein VLA, sondern ein array of unspecified size.
VLA kann man gar nicht initialisieren, sondern nur die Elemente 
zuweisen.

von DPA (Gast)


Lesenswert?

Das bezog sich auf den Gastbeitrag darüber.

von Rolf M. (rmagnus)


Lesenswert?

ein lupenreiner Demokrat schrieb:
> ... schrieb:
>> "Dank" VLA
>
> haben nichts mit dem leeren Array am Strukturende zu tun und sind wieder
> abgeschafft.

Nein, nicht abgeschafft, sondern optional.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

ein lupenreiner Demokrat schrieb:
> und die Länge des Arrays kann man in der Struktur erst ablegen, wenn der
> Speicher für die Struktur (und das Array) reserviert wurde.
1
$ cat foo.c
2
struct foo {
3
        int length;
4
        char data[];
5
};
6
7
struct foo foobar = { .length = 42, .data = { 3, 10, 11, 0 } };
8
$ cc -Wall -Wextra -pedantic -O -S foo.c
9
foo.c:6:45: warning: flexible array initialization is a GNU extension [-Wgnu-flexible-array-initializer]
10
struct foo foobar = { .length = 42, .data = { 3, 10, 11, 0 } };
11
                                            ^
12
foo.c:3:7: note: initialized flexible array member 'data' is here
13
        char data[];
14
             ^
15
1 warning generated.
16
$ cat foo.s
17
        .text
18
        .file   "foo.c"
19
        .type   foobar,@object                  # @foobar
20
        .data
21
        .globl  foobar
22
        .p2align        2
23
foobar:
24
        .long   42                              # 0x2a
25
        .asciz  "\003\n\013"
26
        .size   foobar, 8
27
28
        .ident  "FreeBSD clang version 13.0.0 (git@github.com:llvm/llvm-project.git llvmorg-13.0.0-0-gd7b669b3a303)"
29
        .section        ".note.GNU-stack","",@progbits
30
        .addrsig

Also ja, man kann ein flexible array member standardgemäß so nicht 
initialisieren, nichtstandardgemäß geht es aber schon.

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.