Ich frage mich welchen Sinn Konstanten ergeben? Man könnte doch auch Variablen benutzen und die dann nicht ändern, oder?
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?
:
Bearbeitet durch Moderator
> Warum sind nicht einfach alle Variablen unveränderbar?
..dann wärens ja keine Variablen ('Veränderliche') mehr. Das war jetzt
einfach.
SCNR
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 | const uint8_t *const foo = (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.
1 | #include <stdio.h> |
2 | const int *const foo = (void*) 0x99; |
3 | void main() |
4 | {
|
5 | printf("%d\n", *foo); |
6 | }
|
1 | $ gcc -O3 -o foo foo.c |
2 | $ objdump -d foo | less |
3 | ... |
4 | 0000000000000580 <main>: |
5 | 580: 8b 34 25 99 00 00 00 mov 0x99,%esi |
6 | 587: 48 8d 3d c6 01 00 00 lea 0x1c6(%rip),%rdi # 754 <_IO_stdin_used+0x4> |
7 | 58e: 31 c0 xor %eax,%eax |
8 | 590: e9 cb ff ff ff jmpq 560 <printf@plt> |
bzw. bei AVR:
1 | $ avr-gcc -mmcu=atmega8 -O3 -o foo foo.c |
2 | $ avr-objdump -d foo | less |
3 | ... |
4 | 0000005e <main>: |
5 | 5e: e9 e9 ldi r30, 0x99 ; 153 |
6 | 60: f0 e0 ldi r31, 0x00 ; 0 |
7 | 62: 81 81 ldd r24, Z+1 ; 0x01 |
8 | 64: 8f 93 push r24 |
9 | 66: 80 81 ld r24, Z |
10 | 68: 8f 93 push r24 |
11 | 6a: 82 e6 ldi r24, 0x62 ; 98 |
12 | 6c: 90 e0 ldi r25, 0x00 ; 0 |
13 | 6e: 9f 93 push r25 |
14 | 70: 8f 93 push r24 |
15 | 72: 05 d0 rcall .+10 ; 0x7e <printf> |
16 | ... |
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:
1 | #include <stdint.h> |
2 | |
3 | const __flash uint8_t *const __flash array[] = { |
4 | (const __flash uint8_t []){ 1, 2, 3, 4 }, |
5 | (const __flash uint8_t []){ 5, 6, 7, 8, 9, 10}, |
6 | (const __flash uint8_t []){ 11, 12, 13 } |
7 | };
|
8 | |
9 | uint8_t read_elem(const __flash uint8_t *const __flash *a, |
10 | uint8_t i, uint8_t j) { |
11 | return a[i][j]; |
12 | }
|
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).
:
Bearbeitet durch User
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.