Forum: Compiler & IDEs variables Array in einer struct richtig initialisieren


von Ralf W. (Gast)


Lesenswert?

Hallo,

ich programmiere in C im Atmelstudio 6.2 für den ATMEGA2560.
In einem Header habe ich folgende Strukturen
1
#define ungueltig 4294967295
2
#define namelenght 15
3
4
uint32_t SerienNummer;
5
uint8_t TestschrittAnzahl; // ? Wird im eigentlichen Testprogramm neu deklariert und initialisiert.
6
7
typedef enum{
8
    Spannung,
9
//    AC,
10
//    aBit,
11
//    aByte,
12
    setBit,
13
    resetBit,
14
//    TBReceive,
15
    TBSend,
16
//    TBSendReceive,
17
    TBSeriennummer,
18
    TBSNNetzteil,
19
    TBTuerOeffner,
20
    startTime_s,
21
    stopTime_s,
22
    WaitForDigInHigh,  //wartet bis DigIn(uint8_t mask) == High, setzt Programm dann fort
23
    Delay_ms,
24
}t_eMessArt;
25
26
typedef struct{
27
    t_eMessArt messart;
28
    uint8_t retry;
29
    void *argument;
30
}t_sAction;
31
32
typedef struct{
33
    char name[namelenght];
34
    char min_sign;
35
    char max_sign;
36
    char ist_sign;
37
    uint64_t min;
38
    uint64_t max;
39
    uint64_t ist;
40
    uint8_t actioncount;
41
    bool ausgefallen;
42
    t_sAction actions[];
43
}t_sTestschritt;

Diese werden in einem anderen Header korrekt initialisiert:
1
t_sMessArgument VDC_KL1_KL2Argument = {
2
    .High = E1_H,
3
    .Low = E1_L,
4
    .Range = &Range_200V,
5
    .AC = false,
6
};
7
8
t_sTestschritt VDC_KL1_KL2 = {
9
    .name = "VDC Kl1 Kl2\n",
10
    .min_sign = '-',
11
    .max_sign = '-',
12
    .ist_sign = '-',
13
    .min = 350000000,
14
    .max = 300000000,
15
    .ist = ungueltig,
16
    .actioncount = 1,
17
    .ausgefallen = true,
18
    .actions = {
19
        {.messart = Spannung,
20
         .retry = 3,
21
         .argument = &VDC_KL1_KL2Argument,
22
        }
23
    }
24
};

Jetzt brauche ich aber einen Testschritt t_sTestschritt mit 20 actions.
Ich versuche das so zu deklarieren:
1
t_sAction FileAction[20];
2
3
t_sTestschritt FileTestschritt = {
4
  .actioncount = 20,
5
  .ausgefallen = true,
6
  .actions = FileAction
7
};

Das haut mir aber der Compiler um die Ohren.
1
Warning  1  missing braces around initializer [-Wmissing-braces]  C:\Dokumente und Einstellungen\ralf.COMANCHE\Eigene Dateien\Elektronik\AVR\7573\testprogramm\testschritte.h  67  1  7573
2
Warning  2  (near initialization for 'FileTestschritt.actions') [-Wmissing-braces]  C:\Dokumente und Einstellungen\ralf.COMANCHE\Eigene Dateien\Elektronik\AVR\7573\testprogramm\testschritte.h  67  1  7573
3
Error  3  incompatible types when initializing type 'enum <anonymous>' using type 'struct t_sAction *'  C:\Dokumente und Einstellungen\ralf.COMANCHE\Eigene Dateien\Elektronik\AVR\7573\testprogramm\testschritte.h  67  1  7573

Wie kann ich zur CompileZeit dem Testschritt ein Array von 20 t_sAction 
zuweisen?

von Stefan K. (stefan64)


Lesenswert?

Welche Zeile davon ist die 67?

Gruß, Stefan

von Ralf W. (Gast)


Lesenswert?

Hallo,

Zeile 67 ist die Klammer hinter:

  .actions = FileAction
}; <- Zeile 67

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


Lesenswert?

Ralf W. schrieb:
> Wie kann ich zur CompileZeit dem Testschritt ein Array von 20 t_sAction
> zuweisen?

Gar nicht.

So ein flexible array member besitzt im Rahmen der Struktur selbst
erst einmal keinen Speicher.  Daher kann man auf diese nur dann
zugreifen, wenn sichergestellt ist, dass irgendwo anders her Speicher
dafür bereitgestellt worden ist.  Das bedeutet letztendlich, dass
der ganze Konstrukt nur dann Sinn hat, wenn man auf die Struktur über
Zeiger zugreift.

Sinngemäß findet sich das im Standard in Abschnitt “6.7.2 Type
specifiers”, Absatz 18 wieder:
1
As a special case, the last element of a structure with more than one
2
named member may have an incomplete array type; this is called a flexible
3
array member. In most situations, the flexible array member is ignored.
4
In particular, the size of the structure is as if the flexible array
5
member were omitted except that it may have more trailing padding than
6
the omission would imply. Howev er, when a . (or ->) operator has a left
7
operand that is (a pointer to) a structure with a flexible array member
8
and the right operand names that member, it behaves as if that member
9
were replaced with the longest array (with the same element type) that
10
would not make the structure larger than the object being accessed; the
11
offset of the array shall remain that of the flexible array member, even
12
if this would differ from that of the replacement array. If this array
13
would have no elements, it behaves as if it had one element but the
14
behavior is undefined if any attempt is made to access that element or
15
to generate a pointer one past it.

von Ralf W. (Gast)


Lesenswert?

Hallo,

irgendwie geht es halt doch, wenn ich es so schreibe:
1
t_sTestschritt FileTestschritt = {
2
  .actioncount = 20,
3
  .ausgefallen = true,
4
    .actions = {
5
    {},
6
    {},
7
  }
8
};

Nach meinem dafürhalten habe ich jetzt ein Array für .actions
mit 2 Elementen. Schreibe ich da jetzt 20 leere Klammern habe ich
meine 20 Elemente.
Aber dafür muß es doch eine bessere Schreibweise geben. Oder?

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


Lesenswert?

Ralf W. schrieb:
> Aber dafür muß es doch eine bessere Schreibweise geben. Oder?

Sei doch froh, dass es dafür überhaupt eine gibt.

Dürfte eine GCC-Erweiterung sein, der sich damit also schon mal
über das vom Standard vorgeschriebene Maß hinaus bewegt hat.

von 53453453454353 (Gast)


Lesenswert?

problem ist halt das der vergebene speicher feststehen muss.
deine {} klammern tun das gleiche wie actions[20]

sie reservieren den speicher.

wenn du das dynamisch brauchst dann wirst du um malloc/free nicht 
drumherum kommen.

von Ralf W. (Gast)


Lesenswert?

Hallo,

irgendwie hat Jörg recht. Korrekt muß die struct t_sTestschritt so 
deklariert werden.
1
typedef struct{
2
    char name[namelenght];
3
    char min_sign;
4
    char max_sign;
5
    char ist_sign;
6
    uint64_t min;
7
    uint64_t max;
8
    uint64_t ist;
9
    uint8_t actioncount;
10
    bool ausgefallen;
11
    t_sAction *actions;
12
}t_sTestschritt;

Also das Feld actions wird ein Pointer. Dann kann ich schreiben:
1
t_sAction FileAction[20];
2
3
t_sTestschritt FileTestschritt = {
4
  .actioncount = 20,
5
  .ausgefallen = true,
6
  .actions = FileAction
7
};

Das bricht zwar den anderen Code. Aber den kann ich so umschreiben:
1
t_sMessArgument VDC_KL1_KL2Argument = {
2
    .High = E1_H,
3
    .Low = E1_L,
4
    .Range = &Range_200V,
5
    .AC = false,
6
};
7
8
t_sAction VDC_KL1_KL2Action1 = {
9
    .messart = Spannung,
10
    .retry = 3,
11
    .argument = &VDC_KL1_KL2Argument,
12
};
13
14
t_sTestschritt VDC_KL1_KL2 = {
15
    .name = "VDC Kl1 Kl2\n",
16
    .min_sign = '-',
17
    .max_sign = '-',
18
    .ist_sign = '-',
19
    .min = 350000000,
20
    .max = 300000000,
21
    .ist = ungueltig,
22
    .actioncount = 1,
23
    .ausgefallen = true,
24
    .actions = &VDC_KL1_KL2Action
25
};

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


Lesenswert?

Ralf W. schrieb:
> Korrekt muß die struct t_sTestschritt so deklariert werden.

Du kannst auch das mit dem flexible array member benutzen.  Die
Idee ist dabei dann nur, dass du den eigentlichen Speicher dafür
irgendwo in passender Größe per malloc() beschaffst.  sizeof(struct)
kannst du benutzen, um alles außer dem flexible array zu
bestimmen, d. h. wenn du 20 Elemente im Array hinter der eigentlichen
struct haben willst, allozierst du
1
malloc(sizeof(struct xxx) + 20 * sizeof(array yy))

Davon darfst du dann einen Typecast auf einen Zeiger auf die struct
machen und nun auf den zusätzlichen Speicher am Ende typsicher
zugreifen.

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.