Forum: Mikrocontroller und Digitale Elektronik C: Struct und Array direkt initialisieren


von RS4B5 (Gast)


Lesenswert?

Salu zusammen

Ich habe hier wieder mal ein Problem und blick echt nicht mehr durch. 
Scheint als ob meine C Zeiten auch nicht mehr so aktuell sind. Komm 
einfach nicht drauf. Wäre toll wenn mir jemand eine Lösung hätte.

Zum Problem:

Ich habe einen Stuct deklariert in a.h

typedef struct
{
char a;
char b;
char c[];
} s_x;

extern volatile s_x g_test_array;


Im File a.c möchte ich nun diesen Struct gerne initialisieren (a.h ist 
in a.c includiert):

g_test_array.a = 1;
g_test_array.b = 2;
g_test_array.c[3] = {0x00,0xD4,0x34};

Mööööööp und da will er nicht mehr ;o) Wie initialisiere ich ein Array 
welches sich innerhalb eines Structs befindet wenn ich vorgegebene Werte 
habe? Dass ich es mit einer Schleife initialisieren kann ist mir klar, 
dass habe ich an anderer Stelle auch gemacht und das funktioniert. Also 
ala

for(i=0;i<3;i++)
  g_test_array[i] = 0x00;

So kann ich ja aber kein Array initialisieren. Hoffe ich konnte 
verständlich machen was ich möchte... Wäre toll wenn jemand eine Lösung 
hätte. Bin gerade mit Fonts am basteln und da will ich das irgendwie 
flexiebel gestalten. Ich kann bei der Deklaration des Structs auch nicht 
sagen wie gross das Array "c" werden wird...

Es Grüessli aus der verschneiten Schweiz

RS4B5

von RS4B5 (Gast)


Lesenswert?

Soll natürlich

for(i=0;i<3;i++)
  g_test_array.c[i] = 0x00;

heissen ;o)

Grüessli

von Karl H. (kbuchegg)


Lesenswert?

RS4B5 schrieb:
> Salu zusammen
>
> Ich habe hier wieder mal ein Problem und blick echt nicht mehr durch.
> Scheint als ob meine C Zeiten auch nicht mehr so aktuell sind. Komm
> einfach nicht drauf. Wäre toll wenn mir jemand eine Lösung hätte.
>
> Zum Problem:
>
> Ich habe einen Stuct deklariert in a.h
>
> typedef struct
> {
> char a;
> char b;
> char c[];
> } s_x;

das geht so nicht.
Wie groß ist denn das Array? Da die Größe hier nicht bekannt ist, ist 
damit auch die Strukturgröße nicht bekannt. Ergo weiß der Compiler auch 
nicht, wieviel Platz für eine derartige Variable im Speicher zu 
reservieren ist.

> Ich kann bei der Deklaration des Structs auch nicht
> sagen wie gross das Array "c" werden wird...

Das musst du aber. Denn der Compiler bzw. Linker müssen ja wissen, 
wieviel Speicher sie reservieren müssen.



> Im File a.c möchte ich nun diesen Struct gerne initialisieren (a.h ist
> in a.c includiert):
>
> g_test_array.a = 1;
> g_test_array.b = 2;
> g_test_array.c[3] = {0x00,0xD4,0x34};

Das sind aber keine Initialisierungen. Das sind Zuweisungen.
Du musst Zuweisungen und Initialisierungen streng auseinander halten, 
der Compiler tut das nämlich auch.

volatile s_x g_test_array =
  { 1, 2, { 0x00, 0xD4, 0x34 } };

Initialisierungen stehen IMMER bei der Vereinbarung (der Definition) 
einer Variablen. Dies deshalb, weil Initialisierungen IMMER gemacht 
werden, wenn eine Variable 'zur Welt' kommt.
Alles andere dahinter kann keine Initialisierung mehr sein, sondern ist 
eine Zuweisung. Und Arrays kann man nicht als ganzes zuweisen, sondern 
nur auf Elementebene.

von Krapao (Gast)


Lesenswert?

Deine Deklaration

> extern volatile s_x g_test_array;

könnte bei der Definition so aussehen:

volatile s_x g_test_array = {1, 2, {0x00,0xD4,0x34}};

um die (beim Element c falsche) Laufzeitinitialisierung

> g_test_array.a = 1;
> g_test_array.b = 2;
> g_test_array.c[3] = {0x00,0xD4,0x34};

durch eine Kompilezeitinitialisierung zu ersetzen.

> for(i=0;i<3;i++)
>   g_test_array[i] = 0x00;

Das klappt mit deiner g_test_array Deklaration oben nicht, weil du kein 
Array definiert hast. Eine Arraydeklaration müsste dafür so aussehen:

extern volatile s_x g_test_array[3];

Und bei der entsprechenden Definition wird das Array auch, wenn global, 
vom Startupcode mit 0 initialisiert, so dass du die for-Schleife sparen 
kannst.

von RS4B5 (Gast)


Lesenswert?

Ok, vielen Dank! Jetzt ist es schon klarer... aber ;o)

Nun habe ich in ein anderes Problem

Wie bekomme ich nun diesen Struct Global?

Wenn ich in a.h deklariere

typedef struct
{
char a;
char b;
char c[];
} s_x;

extern volatile s_x g_test_array;


und in a.c über eine Funktion, welche ich aus Main aufrufe 
initialisieren

void Init_struct(void)
{
volatile s_x g_test_array = { 1, 2, { 0x00, 0xD4, 0x34 } };
}

und dann in main auf c zugreifen möchte, geht das nicht? Was hab ich 
denn nun noch nicht verstanden? Entschuldigung, denke ich muss wieder 
mal ein C Buch anschauen

Grüessli

von RS4B5 (Gast)


Lesenswert?

Sorry, die Zeile

extern volatile s_x g_test_array;

im letzten Post müsst ihr euch wegdenken. Ist beim kopieren mitgekommen

von Dosmo (Gast)


Lesenswert?

Bitte Vorsicht!
Mit Deiner Deklaration
1
typedef struct
2
{
3
char a;
4
char b;
5
char c[];
6
} s_x;

wird das Element "c" nur als Pointer definiert und nicht als Array!
Und dieser Pointer enthält noch nicht die Adresse eines geeigneten 
Arrays (denn es gibt ja gar kein Array, weil Du dachtest, Du würdest 
eines anlegen, obwohl Du nur einen Pointer angelegt hast).

Wenn Du nun
1
for(i=0;i<3;i++)
2
  g_test_array.c[i] = 0x00;
ausführst, schreibst Du mit einem uninitialisieren Pointer in Deinem 
Speicher herum (wahrscheinlich die Adresse 0x0000, 0x0001 und 0x0002, 
was immer dort auch liegt, vielleicht SFR?).

von fdssd (Gast)


Lesenswert?

RS4B5 schrieb:
> void Init_struct(void)
> {
> volatile s_x g_test_array = { 1, 2, { 0x00, 0xD4, 0x34 } };
> }

weil es hier bei beenden der funktion gekillt wird
danach ist es nicht mehr existent ..
bzw wurde der speicher wieder freigegeben

wenn du es global machen willst .. tu es doch

1
typedef struct{
2
char a;
3
char b;
4
char c[];
5
} s_x;
6
7
volatile s_x g_test_array = { 1, 2, { 0x00, 0xD4, 0x34 } };
8
9
...main(){
10
}

von Karl H. (kbuchegg)


Lesenswert?

Dosmo schrieb:
> Bitte Vorsicht!
> Mit Deiner Deklaration
>
>
1
> typedef struct
2
> {
3
> char a;
4
> char b;
5
> char c[];
6
> } s_x;
7
>
>
> wird das Element "c" nur als Pointer definiert und nicht als Array!

Ich kann das nur noch einmal unterstreichen. Es sieht nämlich so aus, 
als ob RS4B5 diesen Problemkreis inständig ignoriert.

In C (ausser den neuen dynamischen Arrays) gibt es keine 
Datenstrukturen, die sich irgendwie selbstständig an äussere 
Gegebenheiten anpassen. Wenn du so etwas brauchst, dann musst du das 
selbst machen. Jeder Datentyp (auch eine Struktur ist ein Datentyp) hat 
eine genau definierte Länge und muss die auch haben. Das ist wichtig, 
weil man aus jedem Datentyp wiederrum ein Array machen können muss und 
spätestens dann muss die Größe eines Elements bekannt und auch immer 
gleich sein, sonst funktioniert der ganze Arraymechanismus nicht.

von Stefan E. (sternst)


Lesenswert?

Karl Heinz Buchegger schrieb:
>> wird das Element "c" nur als Pointer definiert und nicht als Array!
>
> Ich kann das nur noch einmal unterstreichen.

Ich nicht, denn es ist falsch.
c ist in dem Beispiel kein Pointer. Es ist ein echtes Array innerhalb 
der Struktur.

Karl Heinz Buchegger schrieb:
> Jeder Datentyp (auch eine Struktur ist ein Datentyp) hat
> eine genau definierte Länge und muss die auch haben.

Und in dem Beispiel ist diese Größe 2 (nur a und b), nicht etwa 4.

Karl Heinz Buchegger schrieb:
> Das ist wichtig,
> weil man aus jedem Datentyp wiederrum ein Array machen können muss und
> spätestens dann muss die Größe eines Elements bekannt und auch immer
> gleich sein, sonst funktioniert der ganze Arraymechanismus nicht.

Richtig, weshalb man auch nicht sinnvoll ein Array aus s_x bilden kann, 
und sofort eine fette Warnung kassiert, wenn man es doch probiert.

von Karl H. (kbuchegg)


Lesenswert?

Stefan Ernst schrieb:
> Karl Heinz Buchegger schrieb:
>>> wird das Element "c" nur als Pointer definiert und nicht als Array!
>>
>> Ich kann das nur noch einmal unterstreichen.
>
> Ich nicht, denn es ist falsch.
> c ist in dem Beispiel kein Pointer.

Ich war mir nicht mehr sicher, was in diesem Fall tatsächlich allokiert 
wird, daher gab ich Dosmo das in dubio.

> Es ist ein echtes Array innerhalb
> der Struktur.

... welches allerdings nicht allokiert wird.

RS4B5 schien der Ansicht zu sein, das er mittels

g_test_array.c[3] = {0x00,0xD4,0x34};

dieses Array nachträglich auf eine Länge von 3 Elementen bringen kann, 
was so natürlich nicht geht. Man kann das machen, wenn man mittels 
malloc sich selbst um den Speicher kümmert. Aber ob der TO diesen Weg 
gehen möchte, wage ich zu bezweifeln.

Auf jeden Fall: Danke für die Korrektur.

von Mark B. (markbrandis)


Lesenswert?

Stefan Ernst schrieb:
> Ich nicht, denn es ist falsch.
> c ist in dem Beispiel kein Pointer. Es ist ein echtes Array innerhalb
> der Struktur.

Und was genau ist ein Array mit einer nicht definierten Zahl von 
Einträgen? Wie viele Einträge gibt es dann?

von Stefan E. (sternst)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Man kann das machen, wenn man mittels
> malloc sich selbst um den Speicher kümmert.

Ich hätte erwartet, dass man die entsprechende Allokierung auch über die 
explizite Initialisierung erreichen kann:
1
volatile s_x g_test_array = { 1, 2, { 0x00, 0xD4, 0x34 } };
Beim GCC funktioniert das auch. Es produziert allerdings auch eine 
Warnung, so dass das vielleicht auch nur eine GCC-Eigenart ist, die 
nicht von Standard abgedeckt ist.

von Karl H. (kbuchegg)


Lesenswert?

Mark Brandis schrieb:
> Stefan Ernst schrieb:
>> Ich nicht, denn es ist falsch.
>> c ist in dem Beispiel kein Pointer. Es ist ein echtes Array innerhalb
>> der Struktur.
>
> Und was genau ist ein Array mit einer nicht definierten Zahl von
> Einträgen? Wie viele Einträge gibt es dann?

Keine. Das Array existiert nur logisch für den Compiler. Aber in der 
Struktur wird kein Speicher dafür reserviert.

Solche Variablen kann man nur verwenden, indem man sich selbst mittels 
malloc entsprechend großen Speicher anlegt.

zb
1
typedef struct
2
{
3
char a;
4
char b;
5
char c[];
6
} s_x;
7
8
9
int main()
10
{
11
  // allokieren und für das Array 3 Elemente anlegen.
12
  s_x *myVar = malloc( sizeof(*myVar) + 3 * sizeof(*(myVar->c)) );
13
14
  s_x->a = 5;
15
  s_x->b = 8;
16
  s_x->c[0] = 'a';
17
  s_x->c[1] = 'b';
18
  s_x->c[2] = 'c';
19
20
  free( myVar );
21
}

d.h. man entlässt den Compiler aus jeglicher Verantwortung für die 
Allokierung. Anders kann man solche Konstrukte nicht sinnvoll verwenden.

von jiffies (Gast)


Lesenswert?

Mark Brandis schrieb:
> Stefan Ernst schrieb:
>> Ich nicht, denn es ist falsch.
>> c ist in dem Beispiel kein Pointer. Es ist ein echtes Array innerhalb
>> der Struktur.
> Und was genau ist ein Array mit einer nicht definierten Zahl von
> Einträgen? Wie viele Einträge gibt es dann?
Ich vermute es geht um diese Punkte:
http://www.dclc-faq.de/kap2.htm

Stefan Ernst schrieb:
> Karl Heinz Buchegger schrieb:
>> Man kann das machen, wenn man mittels
>> malloc sich selbst um den Speicher kümmert.
>
> Ich hätte erwartet, dass man die entsprechende Allokierung auch über die
> explizite Initialisierung erreichen kann:volatile s_x g_test_array = { 1, 2, { 
0x00, 0xD4, 0x34 } };
Lies Karl-Heinz' ersten Beitrag. ;-)

von Stefan E. (sternst)


Lesenswert?

Mark Brandis schrieb:
> Und was genau ist ein Array mit einer nicht definierten Zahl von
> Einträgen? Wie viele Einträge gibt es dann?

Es gibt dann eine zum Zeitpunkt der Definition der Struktur unbestimmte 
Anzahl von Einträgen. Nichtsdestotrotz ist dieses Array aber trotzdem 
innerhalb der Struktur. Wenn du also auf c[42] zugreifst, dann wird 
von der Adresse (Adresse_der_Struktur + 44) gelesen.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Allokierung. Anders kann man solche Konstrukte nicht sinnvoll verwenden.

Wobei ich einschränken muss.

Möglich, dass C99 da etwas definiert hat. Die Entwicklung zu C99 hab ich 
etwas verschlafen, weil ich mich da schon lange auf C++ gestürzt hatte.

von Andreas B. (andreas_b77)


Lesenswert?

Stefan Ernst schrieb:
> Ich hätte erwartet, dass man die entsprechende Allokierung auch über die
> explizite Initialisierung erreichen kann:
1
volatile s_x g_test_array = { 1, 2, { 0x00, 0xD4, 0x34 } };
> Beim GCC funktioniert das auch. Es produziert allerdings auch eine
> Warnung, so dass das vielleicht auch nur eine GCC-Eigenart ist, die
> nicht von Standard abgedeckt ist.

Die statische Initialisierung ist eine Erweiterung. GCC hatte zuvor 
schon zero-length arrays als Erweiterung, die als name[0] (statt name[] 
aus C99) deklariert wurden und ähnlich funktionierten, aber nicht 
statisch initialisiert werden können.

von Dosmo (Gast)


Lesenswert?

>> Stefan Ernst schrieb:
>>> Ich nicht, denn es ist falsch.
>>> c ist in dem Beispiel kein Pointer. Es ist ein echtes Array innerhalb
>>> der Struktur.
>>
>> Und was genau ist ein Array mit einer nicht definierten Zahl von
>> Einträgen? Wie viele Einträge gibt es dann?
>
>Keine. Das Array existiert nur logisch für den Compiler. Aber in der
>Struktur wird kein Speicher dafür reserviert.

Verdammt, hier kann man echt noch was lernen. Ich hätte Stein und Bein 
geschworen, daß "char* a" und "char a[]" das gleiche sind! Hut ab!

von Karl H. (kbuchegg)


Lesenswert?

Dosmo schrieb:

> Verdammt, hier kann man echt noch was lernen. Ich hätte Stein und Bein
> geschworen, daß "char* a" und "char a[]" das gleiche sind! Hut ab!

Nicht an dieser Stelle.
In einer Argmuentliste einer Funktion hättest du recht gehabt.

Aber auch z.b. hier sind die beiden nicht identisch

a.h
1
int values[5];

b.h
1
extern int values[];

c.h
1
extern int* values;

b.h ist korrekt. c.h ist falsch.

Daher: Bei Aussagen, die in der Nähe sind von "Arrays und Pointer sind 
eigentlich dasselbe", ist Vorsicht geboten! Denn ein Array ist kein 
Pointer und ein Pointer ist kein Array.

von Dosmo (Gast)


Lesenswert?

Ja, der von Jiffies genannte Link
http://www.dclc-faq.de/kap2.htm
war sehr aufschlußreich.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:
> Karl Heinz Buchegger schrieb:
>>> wird das Element "c" nur als Pointer definiert und nicht als Array!
>>
>> Ich kann das nur noch einmal unterstreichen.
>
> Ich nicht, denn es ist falsch.
> c ist in dem Beispiel kein Pointer. Es ist ein echtes Array innerhalb
> der Struktur.

Nein. Es ist kein echtes Array, es hat "incomplete type". Man kann also 
zB kein sizeof darauf verwenden.

C99 nennt sowas "flexible array member"; es ist als letzte Komponente 
(und nur dort) von Strukturen erlaubt.

Syntaktisch sieht es auch wie ein char c[] in einer 
Deklaration/Parameterliste, ist semantisch aber was anderes.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Johann L. schrieb:
> C99 nennt sowas "flexible array member"

Das ist übrigens einer der wenigen Punkte, an denen die C-Compiler von 
Microsoft zu C99 kompatibel sind, die unterstützen so etwas auch.

von Martin (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
>> Verdammt, hier kann man echt noch was lernen. Ich hätte Stein und Bein
>> geschworen, daß "char* a" und "char a[]" das gleiche sind! Hut ab!
>
> Nicht an dieser Stelle.
> In einer Argmuentliste einer Funktion hättest du recht gehabt.

Aber auch nur da, als Sonderfall. Überall sonst sind beide 
unterschiedlich.

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.