Forum: Mikrocontroller und Digitale Elektronik AVR: Problem mit array of structs


von Oz z. (ozzy)


Lesenswert?

Moin,

irgendwie stehe ich gerade komplett auf der Stelle... Also, ich habe 
Tabellen im Rom stehen (per PROGMEM) (z.B. const unsigned char Tab1[] 
PROGMEM = {...})
Nun habe ich ein Struct, welches einen Pointer auf die Tabellen 
beinhalten soll, sowie ein paar andere Daten:

1
typedef struct {
2
    unsigned char *Tab;
3
    uint16_t length;
4
    uint16_t Prio;
5
} sStruct;

Nun lege ich ein Paar "Objekte" an :
1
const sStruct sTab1= {Tab1, 50, 1};
2
const sStruct sTab2= {Tab2, 75, 2};
3
...

Und möchte diese nun anschließend in einem Array zusammenfassen:
1
const sStruct[] aTab = {sTab1, sTab2};

Ich bekomme aber immer nur die Fehlermeldung:
1
error: initializer element is not constant
(Zeilennummer von "const sStruct[] aTab = {sTab1, sTab2};")

Ich steige da gerade nicht durch - wo ist denn da der Fehler???

Vielen Dank für Eure Hilfe!!!

von Stefan E. (sternst)


Lesenswert?

1
typedef struct {
2
    const unsigned char * const Tab;
3
    ...

von Oz z. (ozzy)


Lesenswert?

Hi, danke für Deine schnelle Hilfe, aber daran lag es leider nicht...

von ch (Gast)


Lesenswert?

einen 2er in die [] Klammern?

von Oz z. (ozzy)


Lesenswert?

Ne... Daran liegt es auch nicht... Sehe ich den Wald vor lauter Bäumen 
nicht???

von geier99 (Gast)


Lesenswert?

Tab1 muss eine Konstante sein

von Oz z. (ozzy)


Lesenswert?

Moin, ist es doch:
const unsigned char Tab1[] PROGMEM = {...}

von Oz z. (ozzy)


Lesenswert?

Hm,

also wenn ich das
1
const sStruct sTab1= {Tab1, 50, 1};
2
const sStruct sTab2= {Tab2, 75, 2};
3
...
weglasse, und gleich
1
const sStruct[] aTab = {{Tab1, 50, 1}, {Tab2, 75, 2}};
schreibe, geht es ohne Probleme. Warum also mit dem Zwischenschritt 
nicht???

von Fabian O. (xfr)


Lesenswert?

"Zwischenschritt" ist untertrieben. Du legst die Variablen zwei Mal im 
Speicher an. Zuerst sTab1, sTab2 und dann nochmal ein Array mit den 
gleichen Daten. Das ist ja vermutlich nicht, was Du haben möchtest?

von Oz z. (ozzy)


Lesenswert?

Ja, stimmt schon, vom Speicher her ist das besch*** (Pointer wäre da 
wohl besser). Trotzdem interessiert es mich immer noch, warum es nicht 
geht. Eigentlich nur noch für mich...

von Karl H. (kbuchegg)


Lesenswert?

Oz zy schrieb:
> Ja, stimmt schon, vom Speicher her ist das besch*** (Pointer wäre da
> wohl besser). Trotzdem interessiert es mich immer noch, warum es nicht
> geht. Eigentlich nur noch für mich...


Weil das keine Konstante ist.
Achtung: Auch wenn du das ganze Zeugs als const markierst, ist das keine 
Konstante. const bedeutet in C NICHT, dass du eine Konstante definierst, 
sondern nur, dass du per Programm den Wert nicht ändern kannst.

Was du geschrieben hast, ist im Grunde

   int i = 5;
   int j = i;

und i ist nun mal keine compile Time Konstante. Noch nicht mal dann, 
wenn du sie als const markierst.

Der Compiler will an dieser Stelle compile-time Konstante sehen. Also: 
Zahlenwerte, Adressen, Stringliterale. Alles andere sind keine 
Konstante.

von Andreas B. (andreasb)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Was du geschrieben hast, ist im Grunde
>
>    int i = 5;
>    int j = i;
>
> und i ist nun mal keine compile Time Konstante. Noch nicht mal dann,
> wenn du sie als const markierst.
>
> Der Compiler will an dieser Stelle compile-time Konstante sehen. Also:
> Zahlenwerte, Adressen, Stringliterale. Alles andere sind keine
> Konstante.

Sicher?

http://de.wikibooks.org/wiki/C-Programmierung:_Variablen_und_Konstanten

Der Nachteil der Definition von Konstanten mit define ist, dass dem 
Compiler der Typ der Konstante nicht bekannt ist. Dies kann zu Fehlern 
führen, die erst zur Laufzeit des Programms entdeckt werden. Mit dem 
ANSI-Standard wurde deshalb die Möglichkeit von C++ übernommen, eine 
Konstante mit dem Schlüsselwort const zu deklarieren. Im Unterschied zu 
einer Konstanten, die über define definiert wurde, kann eine Konstante, 
die mit const deklariert wurde, bei älteren Compilern Speicherplatz wie 
Variablen auch verbrauchen. Bei neueren Compilern wie GCC 4.3 ist die 
Variante mit const immer vorzuziehen, da sie dem Compiler ein besseres 
Optimieren des Codes erlaubt und die Kompiliergeschwindigkeit erhöht.


mfg Andreas

von Karl H. (kbuchegg)


Lesenswert?

Andreas B. schrieb:
> Karl Heinz Buchegger schrieb:
>
>> Was du geschrieben hast, ist im Grunde
>>
>>    int i = 5;
>>    int j = i;
>>
>> und i ist nun mal keine compile Time Konstante. Noch nicht mal dann,
>> wenn du sie als const markierst.
>>
>> Der Compiler will an dieser Stelle compile-time Konstante sehen. Also:
>> Zahlenwerte, Adressen, Stringliterale. Alles andere sind keine
>> Konstante.
>
> Sicher?

Ja, sicher.

> http://de.wikibooks.org/wiki/C-Programmierung:_Variablen_und_Konstanten

Wer alleine sowas schreibt
1
Mit dem ANSI-Standard wurde deshalb die Möglichkeit von C++ übernommen,
2
eine Konstante mit dem Schlüsselwort const zu deklarieren.
3
Im Unterschied zu einer Konstanten, die über define definiert wurde ...

zeigt schon, dass er da einige Dinge nicht wirklich verstanden hat.

> Der Nachteil der Definition von Konstanten mit define ist,

#define definiert keine Konstanten sondern Textersetzungen. #define hat 
mit 'Konstanten' nicht das geringste zu tun.


const verhindert, dass du dieses hier tun kannst

   const int i = 5;

   ...
   i = 8;

das ist aber auch schon alles. In C ist i nicht gleichwertig mit einer 
compile-time Konstanten. const Variablen sind Variablen, die man nicht 
(legal) verändern kann. Aber nichts desto trotz sind es immer noch 
Variablen und keine compile-time Konstanten. Bei der Benutzung als 
Initializer Elemente tritt dieser Unterschied beispielsweise zu Tage, 
die in C compile time Konstante sein müssen (nicht jedoch in C++!)

von Andreas B. (andreasb)


Lesenswert?

Karl Heinz Buchegger schrieb:
> das ist aber auch schon alles. In C ist i nicht gleichwertig mit einer
> compile-time Konstanten. const Variablen sind Variablen, die man nicht
> (legal) verändern kann. Aber nichts desto trotz sind es immer noch
> Variablen und keine compile-time Konstanten. Bei der Benutzung als
> Initializer Elemente tritt dieser Unterschied beispielsweise zu Tage,
> die in C compile time Konstante sein müssen (nicht jedoch in C++!)

War wohl zu schnell, ja du hast recht. Und ja, ich habe was mit C++ 
durcheinander gebracht, muss das ganze nochmals genauer anschauen.

Auf jeden Fall noch ein kleiner Test:
1
#include <stdio.h>
2
3
int main() {
4
  const int x = 15;
5
  long p = &x;
6
  int * y = p;
7
8
  *y = 30;
9
  
10
  printf("%i\n", x);
11
}

Jaa, dieser Code gibt 30 aus. auch mit -O3.

Man lernt nie aus;-)


mfg Andreas

von Karl H. (kbuchegg)


Lesenswert?

Andreas B. schrieb:


> Jaa, dieser Code gibt 30 aus. auch mit -O3.

Samt einer Warnung
(zumindest sollte das eine Warnung geben)

Und ja, er könnte auch 15 ausgeben. Je nachdem, wie gut der Compiler 
aufgelegt ist. Denn im Grunde hast du hier einen illegal Cast (auch wenn 
du ihn selbst nicht geschrieben hast) und damit werden keine Wetten mehr 
angenommen, welches das richtige Ergebnis ist :-)

In dem Moment, in dem du
  const int x = 15;
schreibst, darf der Compiler diese Zusicherung von dir verwenden (er 
darf, aber er muss nicht).
Deine Zusicherung lautete: x hat den Wert 15 und dieser Wert wird sich 
nicht verändern (daher auch das const). Nur: Wenn du das zusicherst, 
dann solltest du dich auch daran halten und x nicht mehr auf Umwegen 
verändern. Sonst kann das Ärger geben.

von Andreas B. (andreasb)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Andreas B. schrieb:
>
>
>> Jaa, dieser Code gibt 30 aus. auch mit -O3.
>
> Samt einer Warnung
> (zumindest sollte das eine Warnung geben)

Mehr als eine, schon klar;-)

>
> Und ja, er könnte auch 15 ausgeben. Je nachdem, wie gut der Compiler
> aufgelegt ist. Denn im Grunde hast du hier einen illegal Cast (auch wenn
> du ihn selbst nicht geschrieben hast) und damit werden keine Wetten mehr
> angenommen, welches das richtige Ergebnis ist :-)
>
> In dem Moment, in dem du
>   const int x = 15;
> schreibst, darf der Compiler diese Zusicherung von dir verwenden (er
> darf, aber er muss nicht).
> Deine Zusicherung lautete: x hat den Wert 15 und dieser Wert wird sich
> nicht verändern (daher auch das const). Nur: Wenn du das zusicherst,
> dann solltest du dich auch daran halten und x nicht mehr auf Umwegen
> verändern. Sonst kann das Ärger geben.

Ich wollte nur feststellen ob der Wert immer noch als Speicheradresse 
verfügbar ist, oder ob dieser vom Optimizer ggf. irgendwo eingesetzt 
wird.

Ich beschäftige mich öfters mit solchen Themen, und der Optimizer macht 
beim GCC doch noch einiges...

Und ich lerne immer mal wider etwas dazu...

z.B. wenn ich diesen Code (ok, incl. 2 Casts) mit dem g++ kompiliere 
wird 15 ausgegeben. Also hier wird tatsächlich eingesetzt.

Also ist es hier keine Variable mehr. DAS hätte ich erwartet, auch vom 
GCC...


mfg Andreas

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Andreas B. schrieb:
> Ich beschäftige mich öfters mit solchen Themen, und der Optimizer macht
> beim GCC doch noch einiges...

Was soll das bringen, rauszuklamüstern, wie ein Compiler Code übersetzt, 
der undefined oder unspecified behavior hat?

Selbst wenn er so übersetzt wird wie du dir ausmalst, hat das keinerlei 
Allgemeingültigkeit für andere Compiler, Compilerversionen oder 
-schalter.

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.