Forum: Compiler & IDEs Initialisierung eines lokalen Arrays mit Konstanten


von C_programmer (Gast)


Lesenswert?

Hallo,

warum funktioniert das Initialisieren von lokalen statischen Variablen 
nicht mit Konstanten?
1
    static u16 s_u16_buffer[MAX_ANZ][3] ={
2
            {TempMwInit, TempMwInit, TempMwInit},
3
            {TempMwInit, TempMwInit, TempMwInit}
4
    };

MAX_ANZ ist 2
TempMwInit ist eine u16 constante

wenn ich das ganze so initialisiere funktioniert es !!!:
1
    static u16 s_u16_buffer[MAX_ANZ][3] ={
2
            {0, 1, 2},
3
            {3, 4, 5}
4
    };

Warum??

Vielen Dank!

von C_programmer (Gast)


Lesenswert?

Folgende Fehlermeldung erhalte ich vom Compiler:
1
invalid initializer expression

von Karl H. (kbuchegg)


Lesenswert?

C_programmer wrote:

> MAX_ANZ ist 2
> TempMwInit ist eine u16 constante

Leider ist das in C keine Konstante wie in C++, sondern eine Variable 
mit konstantem Wert. Und das macht den Unterschied.

von C_programmer (Gast)


Lesenswert?

>Leider ist das in C keine Konstante wie in C++, sondern eine Variable
>mit konstantem Wert. Und das macht den Unterschied.

Da komme ich nicht ganz mit!
1
const u16 TempMwInit = 120;

ist doch eine konstante?

Warum kann ich diese dann nicht als Initialisierer benutzen?
Oder kommt mir da der Prä-Prozessor dazwischen? Der den "Variablennamen" 
nicht auflöst ?!

Danke!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

C_programmer wrote:
>>Leider ist das in C keine Konstante wie in C++, sondern eine Variable
>>mit konstantem Wert. Und das macht den Unterschied.
>
> Da komme ich nicht ganz mit!
>
1
> const u16 TempMwInit = 120;
2
>
>
> ist doch eine konstante?
>
> Warum kann ich diese dann nicht als Initialisierer benutzen?
> Oder kommt mir da der Prä-Prozessor dazwischen? Der den "Variablennamen"
> nicht auflöst ?!

Nö, der Präprozessor löst keine Variablennamen auf.

Du kannst

1) TempMwInit als Makro definieren
2) Per -DTempMwInit auf der Kommandozeile definieren
3) TempMwInit als lokale static-Variable anlegen
4) Einen Konstruktor schreiben (GNU-Erweiterung) und dort von Hand 
initialisieren, bevor main aufgerufen wird.

Johann

von yalu (Gast)


Lesenswert?

> ist doch eine konstante?

Es ist eine Read-Only-Variable (also das, was Karl Heinz schon vermutet
hat). Solche Variablen (die streng genommen gar nicht variabel sind)
dürfen nicht überschrieben werden, haben aber ansonsten alle
Eigenschaften von gewöhnlichen Variablen. Insbesondere könnte so eine
Variable auch in einer anderen Übersetzungseinheit definiert und in der
aktuellen mit "extern" deklariert werden. Dann kann der Compiler ihren
(konstanten) Wert nicht kennen.

Um solche und ähnliche Probleme zu umgehen, dürfen Variablen (auch
Read-Only-Variablen) generell nicht als Initialisierer von statischen
Variablen verwendet werden. Dort sind nur "direkte" (also lokal
auflösbare) Konstanten erlaubt. Dazu zählen numerische Literale (z.B. 3,
-2.5e-3 usw.), String-Literale, konstante Ausdrücke (z.B. 3+4,
"Text"[3], sizeof-Ausdrücke usw.).

Solche Ausdrücke dürfen auch in Makros verpackt werden. Das ist auch der
gängige Weg, Konstanten mit Namen zu definieren (s. Vorschlag 1 von
Johann).

Johann L. schrieb:

> 3) TempMwInit als lokale static-Variable anlegen

Sicher? Da hast du doch wieder das Problem, dass eine Variable als
Initialisierer verwendet wird.

von Sven P. (Gast)


Lesenswert?

Wenn es numerische Konstanten sind, empfiehlt die Bibel (K&R), statt 
#define lieber enum zu benutzen:
1
/* Nicht: */
2
#define AAA 1
3
#define BBB 2
4
5
/* sondern: */
6
enum {
7
  AAA = 1,
8
  BBB = 2
9
};

Hat dann den Vorteil, dass der Compiler die auch als benannte Konstanten 
(und nicht als Literale) sieht, sagt K&R.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

yalu wrote:
> Johann L. schrieb:
>
>> 3) TempMwInit als lokale static-Variable anlegen
>
> Sicher? Da hast du doch wieder das Problem, dass eine Variable als
> Initialisierer verwendet wird.

Ja, jetzt bin ich sicher. Es geht nämlich auch nicht als static const 
;-)

Sven P. wrote:
> Wenn es numerische Konstanten sind, empfiehlt die Bibel (K&R), statt
> #define lieber enum zu benutzen:
> [...]
> Hat dann den Vorteil, dass der Compiler die auch als benannte Konstanten
> (und nicht als Literale) sieht, sagt K&R.

Kommt auf die Anwendung an. An Makros ist nett, daß man sie überprüfen 
kann, etwa in
1
#if F_CPU % IRQS_PER_SECOND != 0
2
#warning Timer arbeitet ungenau!
3
#endif
4
5
#if F_CPU / IRQS_PER_SECOND > 0xff
6
#error Timer ist nur ein 8-Bit Timer
7
#endif

Mit enums geht das nicht, weil es leider immer noch kein
1
__builtin_error ("Hier ist ein Fehler");
gibt, das man zusammen mit builtin_choose_expr verwenden könnte (und 
wenn, ist's "nur" GNU-C).

Die Typisierung bei Enums kann hilfreich sein (Typprüfungen, Warnungen 
bei switch), oder aber nerven, weil's schlechten Code gibt, z.B. in 
Zusammenhang mit -fshort-enums.

Ich verwende beides, Enums und Makros. Immer das, was am besten passt 
:-)

Johann

von Sven P. (Gast)


Lesenswert?

Johann L. wrote:
> Kommt auf die Anwendung an. An Makros ist nett, daß man sie überprüfen
> kann, etwa in
Das is auch wieder wahr.

> Mit enums geht das nicht, weil es leider immer noch kein[...]
Ist aber nicht mit bedingter Kompilierung zu verwechseln -- auch da 
tendiert der K&R zu ganz gewöhnlichen if() {} und verweist auf den 
Optimierer :-)

> Die Typisierung bei Enums kann hilfreich sein
...wenn sie denn benutzt würde grins abgesehen von switch() mein ich 
(in C, in C++ sieht das schon anders aus).

von c_programmer (Gast)


Lesenswert?

ok, das habe ich jetzt verstanden!
Danke an Alle!

Leider ist es nicht möglich, dass ich den Wert per Define anlege, da der 
Initialisierungsparameter aus einem C-File kommt, welches separat 
ausgetauscht werden kann (Flash Parameter).

In der Header-Datei ist diese Variable als extern deklariert und in dem 
entsprechenden C-File definiert.

Also blieb mir nichts anderes übrig, als den 2D Puffer modul-global zu 
machen und in der Init Funktion des Moduls den Puffer mit dem 
Initialisierungswert zu initialisieren.

Aber danke! Jetzt weiß ich zumindest warum Ansatz 1 falsch war! :-)

Wieder was gelernt!

Ciao!

von c_programmer (Gast)


Lesenswert?

Ah, noch ein Hinweis, warum ich so ein großes "Drum-Herum" um diese 
Initialisierung mache.

Also bei dem Puffer handelt es sich um einen Puffer für einen einfachen 
digitalen Filter. Aber der Filter muss halt mit etwas vernünftigem 
Initialisiert sein, ansonsten ist die "Einschwingzeit" zu groß.

Und mit dem Initialisierungswert aus dem separaten C-File wird eben 
dieser Filter sozusagen konfiguriert.

Ciao

von yalu (Gast)


Lesenswert?

Dann initialisiere den Puffer doch einfach mittels Zuweisungen, dann
hast du die ganzen Probleme nicht.

von c_programmer (Gast)


Lesenswert?

>Dann initialisiere den Puffer doch einfach mittels Zuweisungen, dann
>hast du die ganzen Probleme nicht.

Das habe ich ja damit gemeint, also mit der Initialisierung in der Init 
Funktion des Moduls. Dort habe ich es dann über einmalige Zuweisungen 
gelöst.

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.