Initialisierung eines lokalen Arrays mit Konstanten

Gast #1242781
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!
Gast #1242871
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!
Persönliche Seite #1242980
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
Gast #1242994
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.
Gast #1243010
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.
Persönliche Seite #1243245
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
Gast #1243271
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).
Gast #1243283
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!
Gast #1243306
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
Gast #1243448
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.

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