Flexible Array Member initialisieren in C

Gast #7223527
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.
Beitrag #7223532 wurde von einem Moderator gelöscht.
Gast #7223542
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);
Gast #7223548
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...
Gast #7223566
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
}
Gast #7223595
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.
#7223906
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.
Moderator Persönliche Seite #7224048
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.

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