Forum: PC-Programmierung const value in struktur


von Sara (Gast)


Lesenswert?

Hallo,

ich habe eine Struktur
1
typedef struct
2
{
3
  const uint16_t id;
4
  uint8_t active;
5
  uitn8_t lastError;
6
}parameter_ts

Wenn ich diesen nun initialisiere (für die ganze C-Datei)
1
static parameter_ts parameter[2] =
2
{
3
  {LED_1, 0, 0,},
4
  {LED_2, 0, 0,}
5
};

Hier muss ich für die veränderlichen Variablen ja jetzt eine 0 
einsetzen.
Gibt es eine Möglichkeit, die Struktur in einer Init-Funktion erst zu 
initialisieren ohne das const zu verlieren?

von Klaus W. (mfgkw)


Lesenswert?

In C kann man eine const nicht legal nachträglich noch ändern.
Also beim Initialisieren den const-Wert setzen, und in einer 
init()-Funktion nicht mehr ändern.
(Auch wenn man versuchen kann, das const wegzucasten - kann gehen, muß 
aber nicht und ist nicht schön).

Besser ist es wohl, das Problem anders zu lösen.
Beispielsweise könnte man zur eindeutigen Erkennung nicht eine 
eingebaute id nehmen, sondern implizit die Adresse der struct.

: Bearbeitet durch User
von Klaus W. (mfgkw)


Lesenswert?

Sara schrieb:
> Hier muss ich für die veränderlichen Variablen ja jetzt eine 0
> einsetzen.

PS:
nein, musst du eigentlich nicht.
Beim Initialisieren könntest du auch nur den jeweils ersten Wert für die 
id angeben, und den Rest weglassen.
Dann wird automatisch mit Nullen aufgefüllt.

Die init() könnte dann den Rest machen.

von BobbyX (Gast)


Lesenswert?

Klaus W. schrieb:

> Besser ist es wohl, das Problem anders zu lösen.
> Beispielsweise könnte man zur eindeutigen Erkennung nicht eine
> eingebaute id nehmen, sondern implizit die Adresse der struct.

Oder index der struct in einem Array.

von A. S. (Gast)


Lesenswert?

In der Praxis ist das Problem oft anders herum: Wenn ein Element const 
ist, packt der Linker alles ins const-Segment. (Das kann man aber lösen)

Prinzipiell kannst Du auch const-Werte ändern. Es spricht nicht Mal 
etwas dagegen. const volatile ist ja auch möglich.

Es muss nur sicher sein, dass kein Programmteil "darauf reinfällt". Und 
damit öffnen wir das Feld des U.B.

von Programmierer (Gast)


Lesenswert?

A. S. schrieb:
> In der Praxis ist das Problem oft anders herum: Wenn ein Element
> const
> ist, packt der Linker alles ins const-Segment. (Das kann man aber lösen)

Nein, nur wenn die Variable selbst, also das "parameter", const ist. 
Wäre sonst ein ziemlich nutzloser Linker!

A. S. schrieb:
> Prinzipiell kannst Du auch const-Werte ändern.

Aber nur in C. In C++ ist es verboten, und kann zu 
UB/Programmabsturz/whatever führen, eben z.B. weil der Linker die 
const-Variable (klingt wie gerade Kurve) in einen Read-Only-Bereich 
(Flash?) gemappt hat.

von Klaus W. (mfgkw)


Lesenswert?

Programmierer schrieb:
> Aber nur in C. In C++ ist es verboten, und kann zu
> UB/Programmabsturz/whatever führen, eben z.B. weil der Linker die
> const-Variable (klingt wie gerade Kurve) in einen Read-Only-Bereich
> (Flash?) gemappt hat.

Das kann dir in C genauso passieren.

von Programmierer (Gast)


Lesenswert?

Klaus W. schrieb:
> Das kann dir in C genauso passieren.

Da bin ich mir nicht so sicher. IIRC sind const-Daten in C einfach nur 
"Variablen die man nicht direkt zuweisen kann", aber sobald man das 
const wegcastet, darf man sie verändern.

von A. S. (Gast)


Lesenswert?

Programmierer schrieb:
> IIRC sind const-Daten in C einfach nur
> "Variablen die man nicht direkt zuweisen kann", aber sobald man das
> const wegcastet, darf man sie verändern.

Aber der Linker kann sie direkt ins ROM packen. Macht ja dort Sinn, wo 
das ROM genauso schnell wie RAM gelesen werden kann.

von Programmierer (Gast)


Lesenswert?

A. S. schrieb:
> Aber der Linker kann sie direkt ins ROM packen.

Ist das vom Standard erlaubt? Macht Compiler/Linker das nicht nur, wenn 
er sicher ist dass nirgendwo umgecastet wird, was auch nur dann geht 
wenn es "static" ist? Mir ist als wäre da was...

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


Lesenswert?

Programmierer schrieb:
> sobald man das const wegcastet

… hast du eine UB.

von Noch ein Kommentar (Gast)


Lesenswert?

Problem ist wohl, der Standard benutzt "const" für 2 unterschiedliche 
Aufgaben.

Als Ersatz für das #define. Hier sollen Compiler, Linker... alle Arten 
von Performance Optimierungen machen. Bei denen Zuweisungen und casts 
natürlich nicht klappen können.

Als Zusicherung. Die Komponenten, die dein Programm benutzt, werden 
deine Daten nicht verändern. In diesem Fall soll beides funktionieren. 
Ganz egal, ob du der aufgerufenen Funktion einen const Pointer oder 
einen normalen Pointer übergibst.

von Oliver S. (oliverso)


Lesenswert?

Noch ein Kommentar schrieb:
> Problem ist wohl, der Standard benutzt "const" für 2
> unterschiedliche
> Aufgaben.
>
> Als Ersatz für das #define.

Das ist weder für C noch für C++ der Fall. Der Standard ist (auch) da 
sehr präzise.

Und eigentlich gibt es auch gar kein Problem.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Oliver S. schrieb:
> Noch ein Kommentar schrieb:
>> Problem ist wohl, der Standard benutzt "const" für 2
>> unterschiedliche
>> Aufgaben.
>>
>> Als Ersatz für das #define.
>
> Das ist weder für C noch für C++ der Fall.

In C++ ist es der Fall. Dort ist etwas, das als const definiert ist, 
eine echte Compilezeit-Konstante. In C ist es nur eine Variable, die man 
nicht verändern darf.

Programmierer schrieb:
> IIRC sind const-Daten in C einfach nur "Variablen die man nicht direkt
> zuweisen kann", aber sobald man das const wegcastet, darf man sie
> verändern.

Teil 1 stimmt, Teil 2 nicht.

Programmierer schrieb:
> A. S. schrieb:
>> Aber der Linker kann sie direkt ins ROM packen.
>
> Ist das vom Standard erlaubt?

Ja. Es ist dem Compiler erlaubt, Sachen die const sind, an Stellen 
abzulegen, die keinen Schreibzugriff erlauben. Wobei das bei einer 
struct, in der nur eins von mehreren Elementen const ist, in der Regel 
nicht passieren wird, da die Elemente nicht einfach auf völlig 
unterschiedliche Speicherregionen verteilt werden können.
Es ist dem Compiler auch erlaubt, anzunehmen, dass eine als const 
deklarierte Variable niemals verändert wird und basierend auf dieser 
Annahme Dinge zu optimieren.

> Macht Compiler/Linker das nicht nur, wenn er sicher ist dass nirgendwo
> umgecastet wird, was auch nur dann geht wenn es "static" ist? Mir ist als
> wäre da was...

Ein Compiler darf das machen, wenn er will. Der Standard verbietet das 
nicht, aber er erfordert es auch nicht. Tatsächlich darf der 
Compiler/Linker in dem Fall machen, was er will - undefiniertes 
Verhalten eben.

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


Lesenswert?

Rolf M. schrieb:
>>> Als Ersatz für das #define.
>>
>> Das ist weder für C noch für C++ der Fall.
>
> In C++ ist es der Fall. Dort ist etwas, das als const definiert ist,
> eine echte Compilezeit-Konstante.

Allerdings kann ein #define natürlich viel mehr, als nur Konstanten zu 
definieren. Insofern ist "const" (oder "constexpr") nun nicht wirklich 
ein Ersatz. C++ hat sich an anderen Stellen sehr bemüht, den 
Präprozessor auch sonst noch vermeidbar zu machen, aber das ist nun 
jenseits von "const".

von Rolf M. (rmagnus)


Lesenswert?

Jörg W. schrieb:
> Rolf M. schrieb:
>>>> Als Ersatz für das #define.
>>>
>>> Das ist weder für C noch für C++ der Fall.
>>
>> In C++ ist es der Fall. Dort ist etwas, das als const definiert ist,
>> eine echte Compilezeit-Konstante.
>
> Allerdings kann ein #define natürlich viel mehr, als nur Konstanten zu
> definieren. Insofern ist "const" (oder "constexpr") nun nicht wirklich
> ein Ersatz.

Ja, ich bin jetzt davon ausgegangen, dass es nur um diesen einen 
spezifischen Anwendungsfall von #define geht. Dass const nicht alle 
Anwendungsfälle davon ersetzt, ist eigentlich offensichtlich.

von A. S. (Gast)


Lesenswert?

Rolf M. schrieb:
> Ja, ich bin jetzt davon ausgegangen, dass es nur um diesen einen
> spezifischen Anwendungsfall von #define geht. Dass const nicht alle
> Anwendungsfälle davon ersetzt, ist eigentlich offensichtlich

Es ist eher anders rum: const wurde in seiner Bedeutung erweitert, dass 
man es als Ersatz für #define nutzen kann. Es ist aber weder notwendig 
noch vorgesehen, eine const-Variable zur Compile- oder Linkzeit zu 
kennen.

Also erlaubt C++ es dem Compiler, dann (und natürlich nur dann) wenn er 
es kennt, den Wert der const Variablen literal zu verwenden.

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


Lesenswert?

Wobei man in C++ (anders als in C) einen const-Wert als Größe für eine 
Array-Definition benutzen kann (auch auf globaler/statischer Ebene) – 
wie soll das gehen, wenn der Wert dem Compiler nicht bekannt ist?

Also
1
const int size = 42;
2
int array[size];

compiliert in C++, nicht aber in (Standard-)C.

Wenn ich in C++ die Initialisierung entferne, bekomme ich einen Fehler:
1
const int size;
2
int array[size];
1
$ c++ -c foo.C
2
foo.C:1:11: error: default initialization of an object of const type 'const int'
3
const int size;
4
          ^
5
               = 0
6
1 error generated.

: Bearbeitet durch Moderator
von Rolf M. (rmagnus)


Lesenswert?

A. S. schrieb:
> Es ist eher anders rum: const wurde in seiner Bedeutung erweitert, dass
> man es als Ersatz für #define nutzen kann. Es ist aber weder notwendig
> noch vorgesehen, eine const-Variable zur Compile- oder Linkzeit zu
> kennen.
>
> Also erlaubt C++ es dem Compiler, dann (und natürlich nur dann) wenn er
> es kennt, den Wert der const Variablen literal zu verwenden.

Der Punkt ist, dass C++ das dem Compiler nicht nur erlaubt, sondern ihn 
im Gegensatz zu C auch dazu verpflichtet.

Jörg W. schrieb:
> Wobei man in C++ (anders als in C) einen const-Wert als Größe für eine
> Array-Definition benutzen kann (auch auf globaler/statischer Ebene) –
> wie soll das gehen, wenn der Wert dem Compiler nicht bekannt ist?

Eben. Oder auch als Template-Parameter, die ausschließlich zur 
Compilezeit exitieren.

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

Rolf M. schrieb:
> sondern ihn im Gegensatz zu C auch dazu verpflichtet.

Ich verstehe was Du meinst: muss wenn kann (also soll). Ich hätte "soll" 
statt "erlaubt" schreiben müssen.

Es ist jedoch ok, wenn er nicht kann (weil er dann "nicht muss"=nicht 
verpflichtet ist). Dann liest er den Wert zur Laufzeit. Oder wirft eine 
Fehlermeldung wie bei Jörg, wo er hätte können müssen.


Es soll halt nicht der Eindruck entstehen, dass irgendein Vodoo alle 
consts wegoptimiert oder wegoptimieren könnte.

von Rolf M. (rmagnus)


Lesenswert?

Er kann die Konstanten nicht auflösen, wenn sie nur deklariert, aber wo 
anders definiert sind. also bei folgendem Beispiel ist b ok, aber a 
nicht:
1
extern const int i;
2
const int j = 5;
3
4
char a[i];
5
char b[j];

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


Lesenswert?

A. S. schrieb:
> Es soll halt nicht der Eindruck entstehen, dass irgendein Vodoo alle
> consts wegoptimiert oder wegoptimieren könnte.

Da stimme ich dir natürlich zu. Es ist ja auch gar nicht immer möglich 
oder sinnvoll, da alles "weg zu optimieren". Einfache Konstanten 
allerdings (also irgendwelche Zahlen und dergleichen) lassen sich 
allerdings praktisch immer optimieren, und das kann mit "const" eben 
auch ein C-Compiler tun.

von W.S. (Gast)


Lesenswert?

Sara schrieb:
> ich habe eine Struktur... typedef...

Nein, du hast eine Umbenennung. Und zwar von einem Typnamen zu einem 
zusätzlichen zweiten Typnamen. (der erste kann auch namenlos sein)

Der entscheidende Punkt ist, daß das alles im Bereich der 
Typbezeichnungen ist und nicht im Bereich der Deklaration von Variablen 
oder Konstanten. Begreife so etwas mal. Ein Variablentyp ist lediglich 
eine Vereinbarung mit dem Compiler. Ob du hingegen später damit eine 
Variable oder ein Konstante anlegen willst, ist an dieser Stelle nicht 
relevant.

Soviel zum Prinzip.
Nun stelle dir mal vor, daß du mit deinem Typ eine Variable anlegen 
willst. Und weil wir hier im mikrocontroller.net sind, stehen da zwei 
Medien zur Verfügung: RAM oder ROM(Flash). Wenn es eine Variable sein 
soll, dann wird man dort auch einen Wert hineinschreiben wollen. Also 
RAM, vielleicht auf dem Stack als lokale Variable oder im Heap. Aber wie 
kommt da ein von dir gewünschter konstanter Inhalt hinein? Von Harry 
Potter hineingehext? Oder wie stellst du dir so etwas vor?

W.S.

von Oliver S. (oliverso)


Lesenswert?

Rolf M. schrieb:
> In C++ ist es der Fall. Dort ist etwas, das als const definiert ist,
> eine echte Compilezeit-Konstante.

Auch C++ kennt const volatile, und für die wirklich konstanten 
Konstanten dann noch constexpr.

Oliver

von Klaus W. (mfgkw)


Lesenswert?

Oliver S. schrieb:
> Auch C++ kennt const volatile, und für die wirklich konstanten
> Konstanten dann noch constexpr.

Genau.

Und als Sahnehäubchen sogar mutable. Das macht aus einem const wieder 
ein nicht-const :-)

von root (Gast)


Lesenswert?

>>>In C++ ist es der Fall. Dort ist etwas, das als const definiert ist,
>>>eine echte Compilezeit-Konstante. In C ist es nur eine Variable, die man
>>>nicht verändern darf.

stimmt, in der Praxis aber UB => do not use, fertig.

In C mache ich mir keine Gedanken darüber.Globale, statische oder
Stackvariablen lassen sich über {.id = LED1} initialisieren, der Rest
kann später zur Laufzeit gesetzt werden. Bei malloc und anderen
dynamisch Erzeugten Objekten ist das schlicht unbenutzbar.

In C++ gibt es Klassen dafür. Die Kontanten können durch
die Klassenhierarchie durchgereicht werden.

von Rolf M. (rmagnus)


Lesenswert?

Klaus W. schrieb:
> Und als Sahnehäubchen sogar mutable. Das macht aus einem const wieder
> ein nicht-const :-)

Nicht so ganz. Es macht etwas nicht-const, auch wenn es Teil von etwas 
größerem ist, das eigentlich const ist. Es ist genau für den 
entgegengesetzten Fall zu dem im Ursprungsposting.

root schrieb:
>>>>In C++ ist es der Fall. Dort ist etwas, das als const definiert ist,
>>>>eine echte Compilezeit-Konstante. In C ist es nur eine Variable, die man
>>>>nicht verändern darf.
>
> stimmt, in der Praxis aber UB => do not use, fertig.

Der Punkt ist nicht das UB (das es in C und C++ gleichermaßen gibt), 
sondern dass man in C eine const-Variable an den Stellen, wo eine 
Compilezeit-Konstante notwendig ist, gar nicht verwenden kann, während 
man das in C++ sehr wohl kann.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Rolf M. schrieb:
> sondern dass man in C eine const-Variable an den Stellen, wo eine
> Compilezeit-Konstante notwendig ist, gar nicht verwenden kann, während
> man das in C++ sehr wohl kann.

Auch da ist der Standard sehr präzise: In C++ sind const-Variablen 
"constant expressions", in C nicht.

Oliver

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.