Magnus schrieb:> Ich frage mich welchen Sinn Konstanten ergeben? Man könnte doch auch> Variablen benutzen und die dann nicht ändern, oder?
Bei Konstanten sagt Dir der Compiler, dass Du gerade fälschlicher Weise
versuchst, eine Variable zu ändern, die Du garnicht ändern wolltest.
Ausserdem machen Konstanten Code lesbarer, weil der Leser den Code nicht
auf Seiteneffekt auf Konstanten prüfen muss.
In der embedded Welt kommt noch hinzu, dass Konstanten auch im deutlich
günstigeren Flash liegen können. Bzw. können Konstanten evtl. sogar
komplett aus dem Code entfernt werden.
Neben den bereits von Torsten genannten Gründen:
Das Wissen, dass sich ein Wert nicht ändert, gibt dem Compiler
zusätzliche Optimierungsmöglichkeiten.
Die Verfechter funktionaler Programmiersprachen stellen sich die
umgekehrte Frage: Warum sind nicht einfach alle Variablen unveränderbar?
Magnus schrieb:> Ich frage mich welchen Sinn Konstanten ergeben?
Nun, sie vereinfachen das Verständnis für Physik.
Allerdings fragen sich inzwischen namhafte Wissen-
schaftler, ob Konstanten wie die Lichtgeschwindig-
keit auch wirklich auf Dauer konstant sind.
"Allerdings fragen sich inzwischen namhafte Wissen-
schaftler, ob Konstanten wie die Lichtgeschwindig-
keit auch wirklich auf Dauer konstant sind."
Kurt, bist du wieder Incognito unterwegs...? ;-)
g457 schrieb:>> Warum sind nicht einfach alle Variablen unveränderbar?>> ..dann wärens ja keine Variablen ('Veränderliche') mehr. Das war jetzt> einfach.
Man nennt sie trotzdem Variablen, weil sie zwar nicht veränderbar sind,
trotzdem aber abhängig von vorangegangenen Berechnungen unterschiedliche
Werte annehmen können (ähnlich den Variablen in der Mathematik).
Noch etwas zur Begrifflichkeit:
Man sollte, wenn man im Softwarebereich von Konstanten spricht, zwischen
Compilezeitkonstanten und unveränderbaren (engl. immutable) Variablen
unterscheiden. In C++ bspw. werden zwar beide mit const deklariert,
der Unterschied besteht aber dennoch.
Hier ist noch ein weiterer Grund für Konstanten: Auch ein Literal wie
42 ist eine Konstante, genauer gesagt sogar eine Compilezeitkonstante.
Ohne Literale könnten Variablen nicht (oder höchstens über
Benutzerinteraktion) initialisiert werden.
Magnus schrieb:> Man könnte doch auch> Variablen benutzen und die dann nicht ändern, oder?
Das ist doch längst so:
Toleranzen summieren sich stets nach der ungünstigsten Seite.
Alle Konstanten sind variabel.
Wenn n-1 von n Schrauben gelöst sind, stellt es sich heraus, daß man das
falsche Gerät geöffnet hat.
Maßeinheiten werden immer in den ungebräuchlichsten Dimensionen
angegeben, z.B. Geschwindigkeiten in Angström pro Woche.
In allen Überlegungen ist diejenige Größe die Häufigste Fehlerquelle,
die vorher über jeden Zweifel erhaben war.
Gleiche Teile, unter gleichen Vorraussetzungen geprüft, verhalten sich
im Einsatz unterschiedlich.
Die Ausfallwarscheinlichkeit eines Bauteils ist umgekehrt proportional
zu seiner Zugänglichkeit.
z.B. hier: https://murphyslaws.net/german.htm
Yalu X. schrieb:> Noch etwas zur Begrifflichkeit:>> Man sollte, wenn man im Softwarebereich von Konstanten spricht, zwischen> Compilezeitkonstanten und unveränderbaren (engl. immutable) Variablen> unterscheiden. In C++ bspw. werden zwar beide mit const deklariert,> der Unterschied besteht aber dennoch.
Diese Betrachtung ist zwar richtig, aber da fehlt noch was, was dieses
selten dämliche C/C++ aus vollkommen unerfindlichen Gründen einfach
nicht kennt: tatsächliche Laufzeitkonstanten.
Nur ist die Realität: Es gab sowas eigentlich seit Anbeginn der
Computerzeit: Das sind einfach Konstanten im ROM (heutzutage natürlich
typisch im Flash-ROM, womit sie dann u.U. doch wieder irgendwie variabel
werden...)
Yalu X. schrieb:> Man sollte, wenn man im Softwarebereich von Konstanten spricht, zwischen> Compilezeitkonstanten und unveränderbaren (engl. immutable) Variablen> unterscheiden. In C++ bspw. werden zwar beide mit const deklariert,> der Unterschied besteht aber dennoch.
Das ist aber nicht mehr ganz aktuell: Konstanten, die schon zur
Compile-Zeit bekannt sind, sollten besser als constexpr definiert
werden.
c-hater schrieb:> Diese Betrachtung ist zwar richtig, aber da fehlt noch was, was dieses> selten dämliche C/C++ aus vollkommen unerfindlichen Gründen einfach> nicht kennt: tatsächliche Laufzeitkonstanten.
Was verstehst Du da drunter?
jz23 schrieb:> Konstanten, die schon zur Compile-Zeit bekannt sind, sollten besser> als constexpr definiert werden.
Stimmt, das hatte ich gerade verdrängt ;-)
Damit ist die Unterscheidung zwischen den beiden Konstantenarten auch in
der Syntax angekommen.
c-hater schrieb:> Diese Betrachtung ist zwar richtig, aber da fehlt noch was, was dieses> selten dämliche C/C++ aus vollkommen unerfindlichen Gründen einfach> nicht kennt: tatsächliche Laufzeitkonstanten.>> Nur ist die Realität: Es gab sowas eigentlich seit Anbeginn der> Computerzeit: Das sind einfach Konstanten im ROM
Weder die C- noch die C++-Norm machen Vorgaben darüber, ob und in
welchem Speichertyp Konstanten abgelegt werden müssen. Das ist auch gut
so, denn wäre vorgeschrieben, Konstanten grundsätzlich im ROM/Flash zu
speichern, dürfte man bei der PC-Programmierung, um die es in diesem
Unterforum geht, keine Konstanten verwenden. Das wäre doch schade, oder
meinst du nicht?
Yalu X. schrieb:> Weder die C- noch die C++-Norm machen Vorgaben darüber, ob und in> welchem Speichertyp Konstanten abgelegt werden müssen.
Eben, genau das ist ja das Problem. C kennt einfach keine Speichertypen.
Bemerkenswerter Mangel. Insbesondere in Anbetracht des
Entstehungszeitpunkts der Sprache. Schon damals ein krasses
Fehldesign...
> Das ist auch gut> so, denn wäre vorgeschrieben, Konstanten grundsätzlich im ROM/Flash zu> speichern, dürfte man bei der PC-Programmierung, um die es in diesem> Unterforum geht, keine Konstanten verwenden.
Nö, man könnte dann nur keine echten Konstanten verwenden, sondern
müsste halt auf das Ausweichen, was dann noch möglich ist: allein durch
Konvention zu Pseudo-"Konstanten" verballhornte Variablen. Die natürlich
bei jedem Fehler im Programm doch wieder überschrieben werden könnten...
Im übrigen gäbe es auch bei der PC-Programmierung durchaus
Anwendungsbereiche für echte Konstanten. Schließlich wird in durchaus
sicherheitskritischen Bereichen (nämlich beim Systemstart, wenn das OS
noch schutzlos ist, weil noch garnicht geladen) Code ausgeführt und der
stammt aus einem (Flash-)ROM.
Ja, heute typischerweise aus einem serielle Flash, der in den RAM
entpackt wird. Sicherheitslücke 1. Kategorie. Das schafft (zusammen mit
diesem C-Schmutz) einen Haufen Ansatzpunkte zur Manipulation des
Bootcodes und damit zu Manipulation des OS, noch bevor es gestartet ist.
Weil Code und Konstanten halt nicht wirklich verläßlich konstant sind,
wenn der Kram im RAM liegt...
c-hater schrieb:> Im übrigen gäbe es auch bei der PC-Programmierung durchaus> Anwendungsbereiche für echte Konstanten.
Bei der ist das gar nicht so ein großes Problem, da PCs üblicherweise
mit mehr oder weniger ernstgemeinten Betriebssystemen arbeiten, die
Speicherschutz bieten. Und damit ist es möglich, "konstante" Daten in
einem Speicherbereich unterzubringen, den das Programm selbst nicht
beschreiben kann.
c-hater schrieb:> C-Schmutz
Lass' doch einfach diese nutzlosen und dümmlichen Kommentare stecken.
Rufus Τ. F. schrieb:> c-hater schrieb:>> Im übrigen gäbe es auch bei der PC-Programmierung durchaus>> Anwendungsbereiche für echte Konstanten.>> Bei der ist das gar nicht so ein großes Problem, da PCs üblicherweise> mit mehr oder weniger ernstgemeinten Betriebssystemen arbeiten, die> Speicherschutz bieten. Und damit ist es möglich, "konstante" Daten in> einem Speicherbereich unterzubringen, den das Programm selbst nicht> beschreiben kann.
Das ist aber garnicht so einfach. Nimm folgendes C++
extern volatile int V;
const int I = V;
I wird erst zur Laufzeit initialisiert, also nach Load-Time, und daher
kann es nicht in .rodata o.ä. abgelegt werden, also in Speicher, der
z.B. physikalisch nicht beschrieben werden kann. Das Zeug kommt also
z.B.nach .bss, und es dürfte für ein OS nicht einfach sein,
festzustellen, welche der Daten in .bss und .data etc. ab main() nicht
mehr verändert werden. Allerdings hat man in Assembler das gleiche
Problem.
> c-hater schrieb:>> C-Schmutz>> Lass' doch einfach diese nutzlosen und dümmlichen Kommentare stecken.
+1
c-hater schrieb:> Diese Betrachtung ist zwar richtig, aber da fehlt noch was, was dieses> selten dämliche C/C++ aus vollkommen unerfindlichen Gründen einfach> nicht kennt: tatsächliche Laufzeitkonstanten.
Kann sein, dass ich mich täusche, aber das kann man doch mit einem
pointer auf const machen:
1
constuint8_t*constfoo=(void*)0x99;
Der Compiler optimiert das dann schön raus und trägt direkt die Adresse
ein (uebrigens: bis auf das volatile sind IO Register Aliase ja auch
nichts anderes). Der pointer selbst wird komplett wegoptimiert. Wenn du
jetzt noch ein OS hast, dass dir die Laufzeitkonstanden an diese
Adressen legt (bisschen wie vdso), ist alles wunderbar.
Rufus Τ. F. schrieb:> Bei der ist das gar nicht so ein großes Problem, da PCs üblicherweise> mit mehr oder weniger ernstgemeinten Betriebssystemen arbeiten
Was hast du nicht verstanden an:
> Schließlich wird in durchaus> sicherheitskritischen Bereichen (nämlich beim Systemstart, wenn das OS> noch schutzlos ist, weil noch garnicht geladen)
Magnus schrieb:> Man könnte doch auch> Variablen benutzen und die dann nicht ändern, oder?
ja, könnte man auch und wird auch so funktionieren.
lg. Heiner
Heiner schrieb:> ja, könnte man auch und wird auch so funktionieren
Solange man sie nicht doch (versehentlich) ändert. Das ist der Kern des
Problems, sofern das überhaupt eines ist.
Yalu X. schrieb:> Weder die C- noch die C++-Norm machen Vorgaben darüber, ob und in> welchem Speichertyp Konstanten abgelegt werden müssen
Compiler für den Embedded-Bereich haben i.A. nichtkonforme
Erweiterungen, ohne die man ein Controllersystem kaum sinnvoll
programmieren kann, u.a. auch Befehle für die Zuweisung zu
Speicherarten.
Georg
Ich hätte jetzt gesagt, um nur an einer Stelle einen Wert ändern zu
müssen und nicht den gesamten Quellcode durchsuchen zu müssen ...... bei
selbst definierten Konstanten.
Georg schrieb:> Yalu X. schrieb:>> Weder die C- noch die C++-Norm machen Vorgaben darüber, ob und in>> welchem Speichertyp Konstanten abgelegt werden müssen>> Compiler für den Embedded-Bereich haben i.A. nichtkonforme> Erweiterungen, ohne die man ein Controllersystem kaum sinnvoll> programmieren kann, u.a. auch Befehle für die Zuweisung zu> Speicherarten.
Das ist nichts was man über das Linkerscript nicht lösen kann, dazu
benötigt man keine compilerspezifischen Attribute. Bei Harvard
Architekturen muss man dann allerdings selber aufpassen, dass man die
Daten aus dem Flash auch mit den entsprechenden Instruktionen lädt.
Cyberpunk schrieb:> Georg schrieb:>> Yalu X. schrieb:>>> Weder die C- noch die C++-Norm machen Vorgaben darüber, ob und in>>> welchem Speichertyp Konstanten abgelegt werden müssen>>>> Compiler für den Embedded-Bereich haben i.A. nichtkonforme>> Erweiterungen, ohne die man ein Controllersystem kaum sinnvoll>> programmieren kann, u.a. auch Befehle für die Zuweisung zu>> Speicherarten.>> Das ist nichts was man über das Linkerscript nicht lösen kann, dazu> benötigt man keine compilerspezifischen Attribute.
Dann müsste aber im Linkerskript jede einzelne Variable explizit
eingetragen sein, die nicht im "default"-Speicher landen soll. Da ist es
geschickter, dort nur Speichersektionen zu definieren und im Quellcode
bei der Definition der Variablen anzugeben, in welche Sektion sie soll.
Das Linkerkskript will man in der Regel nicht ständig anfassen müssen.
> Bei Harvard Architekturen muss man dann allerdings selber aufpassen, dass> man die Daten aus dem Flash auch mit den entsprechenden Instruktionen> lädt.
Harvard-Architektur heißt nicht Trennung zwischen Flash und RAM, sondern
zwischen Code- und Datenspeicher. Bei einer echten Harvard-Architektur
lädt man gar keine Daten aus dem Codespeicher, daher gäbe es das Problem
dort gar nicht. Der AVR hat eine modifizierte Harvard-Architektur, bei
der man Daten auch aus dem Programmspeicher lesen kann.
Eine echte Harvard-Architektur wäre für C überhaupt kein Problem.
Rolf M. schrieb:> Dann müsste aber im Linkerskript jede einzelne Variable explizit> eingetragen sein, die nicht im "default"-Speicher landen soll. Da ist es> geschickter, dort nur Speichersektionen zu definieren und im Quellcode> bei der Definition der Variablen anzugeben, in welche Sektion sie soll.> Das Linkerkskript will man in der Regel nicht ständig anfassen müssen.
Ja im Endeffekt meinte ich das. Gut die Variablen müssen dann im
Quelltext in die entsprechende Sektion zugewiesen werden und dazu mit
einem compilerspezifischen Attribut, aber es ist immer noch portabel
(das Makro muss halt angepasst werden).
Rolf M. schrieb:> Harvard-Architektur heißt nicht Trennung zwischen Flash und RAM, sondern> zwischen Code- und Datenspeicher. Bei einer echten Harvard-Architektur> lädt man gar keine Daten aus dem Codespeicher, daher gäbe es das Problem> dort gar nicht. Der AVR hat eine modifizierte Harvard-Architektur, bei> der man Daten auch aus dem Programmspeicher lesen kann.> Eine echte Harvard-Architektur wäre für C überhaupt kein Problem.
Stimmt da hast du natürlich recht, mir war nur nicht bewusst das AVR da
ein wenig speziell ist. Welche Architektur ist den z.B. eine echte
Harvard-Architektur?
Cyberpunk schrieb:> Welche Architektur ist den z.B. eine echte> Harvard-Architektur?
Dass es absolut keinen Zugriff mit Befehlen auf den Codespeicher gibt,
kenne ich von realen CPUs eigentlich nicht, wäre auch recht unpraktisch.
Der DSP 56000 von Motorola wurde mal so tituliert, da er sogar drei
Addressräume hat (P fürs Programm und X und Y für die komplexen Daten).
Intern waren das auch drei getrennte Address/Datenbusse. Es gab aber
trotzdem Befehle, Werte aus P zu lesen und zu schreiben.
Der 8051 ist eigentlich auch Harvard (und RISC, kaum Befehle und keiner
kann was ;) ), der hat aber auch ein MOVC.
Magnus schrieb:> Ich frage mich welchen Sinn Konstanten ergeben? Man könnte doch auch> Variablen benutzen und die dann nicht ändern, oder?
OK, heute ist also ein Quasi-Freitag .. mal wieder.
Der Sinn von Konstanten besteht darin, daß sie einen vorhersehbaren Wert
besitzen. Variablen haben per se erstmal gar keinen vorhersehbaren Wert.
Den bekommen sie nur dadurch, daß man wenigstens einmal was in sie
hineinschreibt.
Das ist der grundlegende Unterschied.
Die heutigen C-Programmierer haben das vergessen, weil sie in ihrer
Beschränkung auf C einfach annehmen, jegliche Variable müßte mit 0
vorinitialisiert sein.
Und zwischen klassischen Variablen und klassischen typisierten
Konstanten in einem PC-Programm gibt es technisch tatsächlich keinen
Unterschied, denn beide sind schlichtweg Variablen im RAM. Die einen
uninitialisiert und die anderen mit Werten vorinitialisiert.
Für die Verhältnisse im µC ist das allerdings nicht wirklich passend.
Dort hätte man typisierte Konstanten oftmals lieber im ROM, wo sie im µC
eigentlicj auch hingehören.
Aber in C ist das oftmals ein Krampf. Hier könnte ein C-Nonhater ja mal
posten, wie man ein konstantes Array von Pointern, die auf jeweils ein
konstantes Feld von irgendwas (z.B. Bytes) in unbekannter Länge
hinzeigen schreibt, so daß alles auch wirklich dorthin kommt, wo es
hinsoll. Dazu dann eine Funktion, die mit einem Zeiger auf dieses Array
im Argument damit zurechtkommt, ohne sowas wie *(arg+7) benutzen zu
müssen, also etwa ne Entsprechung von x:= arg^[7]; ;-)
W.S.
W.S. schrieb:> Hier könnte ein C-Nonhater ja mal posten, wie man ein konstantes Array> von Pointern, die auf jeweils ein konstantes Feld von irgendwas (z.B.> Bytes) in unbekannter Länge hinzeigen schreibt, so daß alles auch> wirklich dorthin kommt, wo es hinsoll. Dazu dann eine Funktion, die> mit einem Zeiger auf dieses Array im Argument damit zurechtkommt, ohne> sowas wie *(arg+7) benutzen zu müssen, also etwa ne Entsprechung von> x:= arg^[7]; ;-)
Hier ein Beispiel für den AVR:
Falls man viele solcher Daten hat, die ins Flash sollen, wird man für
"const __flash" ein Makro und/oder für "const __flash uint8_t" einen Typ
definieren.
Der erzeugte Code für read_elem:
1
read_elem:
2
mov r30,r22
3
ldi r31,0
4
lsl r30
5
rol r31
6
add r30,r24
7
adc r31,r25
8
lpm r0,Z+
9
lpm r31,Z
10
mov r30,r0
11
add r30,r20
12
adc r31,__zero_reg__
13
lpm r24,Z
14
ret
An den drei LPMs erkennt man, dass der Pointer (2 Bytes) und das Element
des Unterarrays (1 Byte) tatsächlich aus dem Programmspeicher gelesen
werden.
Bei Prozessoren mit Von-Neumann-Architektur (wie z.B. dem ARM) entfällt
in obigem C-Code das Schlüsselwort __flash (das const reicht). Man muss
lediglich dafür sorgen, dass der Linker die .rodata-Section ins Flash
legt.
Harald W. schrieb:> Magnus schrieb:>>> Ich frage mich welchen Sinn Konstanten ergeben?>> Nun, sie vereinfachen das Verständnis für Physik.> Allerdings fragen sich inzwischen namhafte Wissen-> schaftler, ob Konstanten wie die Lichtgeschwindig-> keit auch wirklich auf Dauer konstant sind.
Es ist auch hinlänglich bekannt, dass sich Licht je nach Medium in dem
es sich bewegt, eine andere Geschwindigkeit aufweist
(Ausbreitungsgeschwindigkeit).
W.S. schrieb:> Die heutigen C-Programmierer haben das vergessen, weil sie in ihrer> Beschränkung auf C einfach annehmen, jegliche Variable müßte mit 0> vorinitialisiert sein.
Das nehmen C-Programmierer nicht an. Erstens kann man explizit
initialisieren, zweitens sind globale Variablen (auch solche mit
static-scope) tatsächlich bei Abwesenheit expliziter Initialisierung
implizit mit 0 initialisiert, aber drittens sind nicht initialisierte
lokale Variablen überhaupt nicht initialisiert, und deren Lesen ergibt
undefiniertes Verhalten.
W.S. schrieb:> Die heutigen C-Programmierer haben das vergessen, weil sie in ihrer> Beschränkung auf C einfach annehmen, jegliche Variable müßte mit 0> vorinitialisiert sein.
Gerade in C sind (im Gegensatz zu anderen Sprachen) lokale Variablen
eben nicht vorinitialisiert. Somit billiger Trollversuch deinerseits.