Hallo, ich habe die folgende Frage:
Ich möchte in meinem Programm die Adresse einer über #define
festgelegten Konstante anzeigen:
----------------------------
...
#define Konstante 0x027
void *vdptr;
void main ()
{
vdptr = (long unsigned int *) &Konstante;
printf ("Addr von <Konstante> = %p\n", *vdptr);
...
}
----------------------------
Funktioniert natürlich nicht ...!
Wie bitte lautet der korrekte Code-Schnipsel?
Danke im voraus.
> Wie bitte lautet der korrekte Code-Schnipsel?
So gar nicht. Defines sind Präprozessor, Zeiger sind Compiler bzw.
Laufzeit. Was willst Du denn ∗wirklich∗ erreichen?
HTH
Ich möchte
1. im printf Befehl die Adresse des Wertes "0x027" anzeigen lassen und
2. diese Adresse an eine Function übergeben (aber eben nicht mittels
Kontantennamen, sondern über die ermittelte Adresse, bzw. des Pointers,
den ich vorher auf die Adresse setze)
Danke!
der compiler setzt dann "direkt" überall die 0x027 ein. es wird somit
gar keine variable erstellt, in der 0x027 drin steht. keine variable ->
kein speicher für die variable -> keine adresse
es geht also nicht was du vorhast. du musst also vorher künstlich ne
variable kreieren, wie oben von g457 beschrieben.
lg
>> der compiler setzt dann "direkt" überall die 0x027 ein. es wird somit> gar keine variable erstellt, in der 0x027 drin steht. keine variable ->> kein speicher für die variable -> keine adresse>> es geht also nicht was du vorhast. du musst also vorher künstlich ne> variable kreieren, wie oben von g457 beschrieben.>>> lg
Ok - meine ich verstanden zu haben - aber dennoch steht doch eine
Konstante irgendwo im Speicher und hat eine Adresse ...! (Das war meine
Überlegung).
Die Adresse der Konstante 0x027 ist jetzt also unter &ulBar abgelegt,
oder ist die Konstante 0x027 in die Speicherzelle ulBar kopiert worden?
Dann wäre zweimal Speicher für 0x027 verbraucht worden?
Danke!
Das geht so nicht. Was passiert ist, dass der Präprozessor überall in
deinem Quellcode die Zeichenfolge "Konstante" durch die Zeichenfolge
"0x027" ersetzt. Rein textuell, bevor der Compiler losläuft, also als ob
du selbst statt "Konstante" überall "0x027" hättest.
@ Hendrik L. (lbd)
>Ok - meine ich verstanden zu haben -
Irrtum.
> aber dennoch steht doch eine>Konstante irgendwo im Speicher und hat eine Adresse ...! (Das war meine>Überlegung).
Eben WEIL es eine KONSTANTE ist, hier sogar nur ein #define, hat sie
keinen physischen Speicherplatz. Der Wert der Konstante wird in den
jeweiligen Funktionen als Assemblerbefehl mit Konstante übersetzt.
>Die Adresse der Konstante 0x027 ist jetzt also unter &ulBar abgelegt,
Nö, der Pointers.
>oder ist die Konstante 0x027 in die Speicherzelle ulBar kopiert worden?
Ja.
>Dann wäre zweimal Speicher für 0x027 verbraucht worden?
Nö. Die Konstante existiert so nur im Compiler, nicht als Variable im
Speicher des uC.
Danke!
Ulli schrieb:> Das geht so nicht. Was passiert ist, dass der Präprozessor überall in> deinem Quellcode die Zeichenfolge "Konstante" durch die Zeichenfolge> "0x027" ersetzt. Rein textuell, bevor der Compiler losläuft, also als ob> du selbst statt "Konstante" überall "0x027" hättest.
Ok - mein Denkfehler ist also:
Die Konstante steht nicht im "RAM", sondern ist Teil des Quellcodes
geworden?
Hendrik L. schrieb:> Die Konstante steht nicht im "RAM", sondern ist Teil des Quellcodes> geworden?
Genau. Du kannst einem Wert einen Namen geben, nicht mehr, aber auch
nicht weniger (das kann ein sehr mächtiges Werkzeug sein).
Hendrik L. schrieb:> Die Konstante steht nicht im "RAM", sondern ist Teil des Quellcodes> geworden?
richtig... aber genauer gesagt, wird der quellcode ja in assembler
befehle umgewandelt. die 0x027 steht somit direkt in den
assemblerzeilen wo benoetigt... und diese assemblerzeilen stehen (für
gewöhnlich) im flash deines uC
Sina Anargo schrieb:> und diese assemblerzeilen stehen (für> gewöhnlich) im flash deines uC
Natürlich nicht! Die Assemblerzeilen werden assembliert, relocatiert und
gelinkt danach ist es Machinecode, Maschinensprache, Binärcode und das
kommt als *.hex oder *.bin in den Flash
Hendrik L. schrieb:> Ok - meine ich verstanden zu haben - aber dennoch steht doch eine> Konstante irgendwo im Speicher und hat eine Adresse ...! (Das war meine> Überlegung).
Und die ist halt falsch. Nimm an, im Programm steht
1
#define eins 1
2
intn;
3
n=eins;
und der Compiler macht daraus in irgend einem Pseudoassembler
1
n dw 0
2
...
3
clr n
4
inc n
Also: reserviere Platz für die Variable n, lösche sie, inkrementiere
sie. Warum? Keine Ahnung, weil es schneller ist, weil der Prozessor
keine immediate values hat, völlig egal. Entscheidend ist, daß nirgendwo
mehr verlangt ist, als daß nach (!) Ausführen von n=eins die Variable n
den Wert 1 hat. Oder genauer gesagt, daß, wenn mit ihr weitergerechnet
wird, das Programm sich so verhält, als ob dort dann eine 1 enthalten
ist.
>> Die Adresse der Konstante 0x027 ist jetzt also unter &ulBar abgelegt,> oder ist die Konstante 0x027 in die Speicherzelle ulBar kopiert worden?
Letzteres.
>> Dann wäre zweimal Speicher für 0x027 verbraucht worden?
Kann sein, muß aber nicht, siehe oben.
Halten wir doch in vereinfachter Sprechweise fest - auch für alle
Newbies, die diese Frage evtl. noch stellen könnten:
"#define-Konstanten" landen im Hex Code (werden mit den Programm-Code
geflashed) und sind daher nicht adressierbar (bei einer
Harvard-Architektur).
Nur Konstanten im "Variablen-Speicher" (die nicht vorab vom Präprozessor
verarbeitet werden) und in RAM landen, sind wie Variablen (lesend)
adressierbar!
Typischer Befehl, der eine solche Konstante im RAM erzeugt:
const unsigned long ulBar = 0x027;
Ich selbst werde in Zukunft Konstanten über #define vermeiden.
Ihr habt mir sehr geholfen - Vielen Dank an Alle!
Grüße
Hendrik L. schrieb:> "#define-Konstanten" landen im Hex Code (werden mit den Programm-Code> geflashed) und sind daher nicht adressierbar (bei einer> Harvard-Architektur).
"#define-Konstanten" gibt es nicht. #define macht nur eine Textersetzung
im Quellcode.
Bei deinem Beispielprogramm aus dem Ursprungsposting werden als
allererste Operation vom Präprozessor alle Vorkommen von "Konstante"
durch 0x027 ersetzt. Danach kommt erst der eigentliche Compiler dran,
der überhaupt nicht weiß, daß es da mal ein #define gegeben hat. Der
sieht praktisch das:
1
void*vdptr;
2
3
voidmain()
4
{
5
vdptr=(longunsignedint*)&0x027;
6
printf("Addr von <Konstante> = %p\n",*vdptr);
7
8
...
9
}
Und erst dann wird daraus Assembler- bzw. Maschinencode erzeugt.
> Nur Konstanten im "Variablen-Speicher" (die nicht vorab vom Präprozessor> verarbeitet werden) und in RAM landen, sind wie Variablen (lesend)> adressierbar!>> Typischer Befehl, der eine solche Konstante im RAM erzeugt:>> const unsigned long ulBar = 0x027;
Das ist in C allerdings keine echte Konstante. Du kannst sie z.B.
außerhalb einer Funktion nicht als Array-Größe verwenden, weil dort nur
Konstanten erlaubt sind.
> Ich selbst werde in Zukunft Konstanten über #define vermeiden.
Warum? Weil sie keine Adresse haben?
Rolf Magnus schrieb:> "#define-Konstanten" gibt es nicht. #define macht nur eine Textersetzung> im Quellcode.>
Hallo Rolf,
das hatten wir nun schon ein paar Mal- ist klar!
Dennoch kann ich über "#define" Konstanten definieren, die vom Prozessor
als "unveränderlicher Wert" arithmetisch verarbeitet werden! Oder nicht
etwa?!
Insofern ist ja wohl der Begriff in Anführungszeichen "#define
Konstanten" nicht ganz falsch - oder ???
Auch wenn sie nicht im RAM adressierbar sind, weil sie dort gar nicht
gespeichert sind!
Ich schlage vor, wir schliessen diesen Thread - sonst findet ein Newbie
die Kernaussage,
daß die "#define-Konstante" via Präprozessor im Hex Code landet und
daher nicht adressierbar ist,
wieder nicht!
Grüße
Hendrik L. schrieb:> Ich selbst werde in Zukunft Konstanten über #define vermeiden.
In Mikrocontrollern hat man typischerweise deutlich weniger RAM als
Programmspeicher. Also vermeidet man, wo immer es geht, unnötig Daten in
den RAM zu legen.
Numerische Konstanten im RAM sind besonders unnötig, da sie nicht nur
mehr RAM brauchen, sondern auch mehr Programmspeicher. Denn zum einen
müssen sie sowieso zusätzlich im Programmspeicher vorhanden sein, damit
der Startup-Code sie in den RAM kopieren kann. Zum anderen werden sie an
jeder Stelle, an der sie verwendet werden, aus dem RAM geholt, statt als
Immediate-Wert im Maschinenbefehl zu stehen. Dieser Code braucht
normalerweise mehr Platz und wird langsamer ausgeführt.
Es ist also in Mikrocontrollerprogrammen ein großer Vorteil, wenn
Konstanten keine Adresse haben! Daher greift man in C lieber zum Define,
da damit sichergestellt ist, dass kein statischer RAM verbraucht wird.
Bei den meisten Architekturen wird die Konstante als Literalwert direkt
in den Maschinenbefehlen verwurstet. Meist/oft ließe sich davon sogar
tatsächlich eine Adresse (die dann eben im Textsegment läge)
feststellen.
Das "Problem" ist, daß das eben nicht überall und immer geht. Eine
"0"-Konstante beispielsweise wird - so denn vorhanden - in einen
"CLR"-Befehl abgebildet oder auch in ein XOR. Da steht dann nirgends
eine 0, also kann man auch keine Adresse davon bilden. Ähnliches bei
Fließkommakonstanten (PI z.B.), die u.U. direkt im Silizium hart
verdrahtet sind.
Drum kann man von Literalen keine Adresse feststellen. Unter Umständen
gibt's die halt einfach nicht.
Hendrik L. schrieb:> aber dennoch steht doch eine Konstante irgendwo im Speicher> und hat eine Adresse ...!
Teilweise ist das der Fall, ja, etwa bei den Constant-Pools von arm-gcc.
An diese Adresse kommst du aber von C aus *nicht* dran!
0x27 ist auch einfach genug, sie nicht in einem Const-Pool abzulegen und
direkt in Regster zu laden. Aber auch Register (GPRs) sind nicht
adressierbar in C.
A. K. schrieb:> Hendrik L. schrieb:>> Harvard-Architektur>> Mit Harvard v. von-Neumann hat das nichts zu tun.
Bevor Du eine solche Aussage in einem Experten-Forum tätigst, würde ich
mich erst einmal über den Unterschied beider Architekturen informieren!
Grüße
Damit überhaupt klar wird, warum ich die Adressen benötige:
Ich habe eine Vielzahl vom Konstanten, die in einem existierenden
Programm über #define festgelegt sind.
Bei einer Modifikation dieses Programms sollen diese Konstanten nun über
ihre Adresse (zukünftig im RAM) mittels Adress-Aritmetik an universelle
Functions übergeben werden, die sowohl Variablen als auch Konstanten
gleichberechtigt (lesend) verarbeiten.
Obiges Beispiel war lediglich vereinfacht, um nicht 1000ende Zeilen von
Code zu posten.
Ich werde nun also die "#define - Konstanten" in C-Direktiven "const
.... = ..." (ohne Präprozessor-Aktion) auflösen.
Noch einmal vielen Dank, besonders an Euch, HTH und den (Gast) "Ulli".
Ihr habt mir am verständlichsten den entscheidenden Hinweis zu meinem
Denkfehler geben können!
Die restlichen Beiträge waren wahrscheinlich nicht falsch, aber wenig
hilfreich zur eigentlichen Fragestellung.
Aber auch für den Versuch dieser Kollegen bedanke ich mich ausdrücklich
recht herzlich!
Grüße
Über #define werden keine Konstanten definiert. #define mach
TEXT-Ersatz!
Wenn du solche Konstanten brauchst, dann leg sie in ein Array und
übergib die Adresse des entsprechenden Array-Elements, d.h. der Index
bildet auf die Konstante ab.
Evtl. tun es auch einzelne Variablen oder eine Strktur bei
unterschiedlichen Typen; kommt auf die konkrete Problemstellung an.
Falls die Variablen nach der Linkzeit noch verändert werden können, z.B.
durch Kalibrierung, dann müssen diese volatile sein (z.B. const
volatile).
Hendrik L. schrieb:> Bei einer Modifikation dieses Programms sollen diese Konstanten nun über> ihre Adresse (zukünftig im RAM) mittels Adress-Aritmetik an universelle> Functions übergeben werden, die sowohl Variablen als auch Konstanten> gleichberechtigt (lesend) verarbeiten.
Das können Funktionen schon immer, der Compiler kümmert sich automatisch
darum.
In dem einen Fall muß er den Wert erst umständlich vom RAM in das
Register laden, im anderen lädt er einfach das Register direkt mit dem
Wert, was in der Regel schneller ist und weniger Code verbraucht.
Eine Konstante in den RAM zu laden, ist nur dann sinnvoll, wenn sie Teil
eines Arrays ist und man nur den Pointer auf das Array übergibt.
Z.B. Du gibst einen 10 Zeichen Text aus, dann ist natürlich eine
Pointervariable sparsamer als 10 einzelne Byte-Variablen.
Allgemein ist bei Übergabe ab >4 Variablen der Einsatz eines Pointers
auf ein Array zu überlegen.
Noch krasser wird der Aufwand, wenn man auf Biegen und Brechen die
Pointerübergabe für eine einzelne Variable erzwingen will, der Aufrufer
die Variable aber schon in einem Register hat.
Dann muß der Compiler erst einen Stackframe anlegen, dort die Variable
aus dem Register ablegen, einen Pointer darauf laden und nach dem Aufruf
den Stackframe wieder löschen.
Das wird manchmal trotzdem gemacht, nämlich wenn man den neuen Wert der
Variable wieder an den Aufrufer zurück geben muß.
In dem Fall ist meistens aber eine struct als Returnwert effektiver, um
mehr als einen Wert zurück zu geben, z.B. Result + Errorcode.
Hendrik L. schrieb:> A. K. schrieb:>> Hendrik L. schrieb:>>> Harvard-Architektur>>>> Mit Harvard v. von-Neumann hat das nichts zu tun.>> Bevor Du eine solche Aussage in einem Experten-Forum tätigst, würde ich> mich erst einmal über den Unterschied beider Architekturen informieren!
Au weia!
Ich kenne ja A.K. nicht persönlich, aber ich denke, er war persönlich
anwesend, als sich John Neumann und Hank Harvard damals auf ihre
Architekturen geeignigt haben...
DJ Tobsen schrieb:> er war persönlich anwesend
:-)
Auch der Rest von Hendriks Beitrag (um den es bei der Aussage ging)
zeugt eher von hochgradiger Konfusion denn irgendwie Verständnis.
Das ist natürlich sein gutes Recht, sich als offenbarer Anfänger in
der Materie auch mal zu irren, aber dann sollte man mit dem Spucken
großer Bögen (wie in der Bemerkung bezüglich A. K.) mal 'ne Runde
kürzer treten …
Naja, vielleicht ist Hendrik ja noch lernfähig. Irgendwann wird er
dann mal bemerken, dass A. K. eher einer derer ist, die das erste
Wort seines „Expertenforums“ ausmachen. ;-)
Hendrik L. schrieb:> Bevor Du eine solche Aussage in einem Experten-Forum tätigst, würde ich> mich erst einmal über den Unterschied beider Architekturen informieren!
:-)
Hast du mal nachgesehen, auf welchem Weg bei einem ARM7 (v-N) die
Konstante 3840 üblicherweise in einem Register landet? Oder beim Thumb2
Befehlssatz die Konstante 0x12345678, wenns schnell gehen soll. Ganz
abgesehen von Wolfgangs Beispiel mit CLR+INC.
Eigentlich ist es ja ganz einfach:
Man braucht nur im C-Standard nachzusehen, dann ist es völlig
unerheblich, ob man es mit einer Havard- oder von-Neumann-Architektur zu
tun hat, oder ob die Werte im ROM oder RAM ebgelegt werden:
1
The operand of the unary & operator shall be either a function
2
designator, the result of a [] or unary * operator, or an lvalue that
3
designates an object that is not a bit-field and is not declared with
4
the register storage-class specifier.
Ein Integer-Literal (darum handelt es sich bei 0x027) ist nichts von all
dem, also kann auch der Adressoperator nicht darauf angewendet werden.
Auch wenn das Integer-Literal in ein Makro eingepackt wird, bleibt es
aus der Sicht des C-Compilers ein Integer-Literal, da dieser nur den
vollständig präprozessierten Code zu Gesicht bekommt.
Zum Thema Konstanten muss ich jetzt aber auch mal sagen:
Ich hab mal Motorsteuergeräte programmiert. Diese hatten einen sehr
umfangreichen Konfigurationsparametersatz (mit den Kennlinien,
Reglerbeiwerten etc.). Die Konfigparameter wurden als "echte Konstanten"
realisiert, d.h. jeder Wert war als Instanz im Flash mit fester Adresse
vorhanden und der Zugriff erfolgte über diese Adresse.
Um die Konfiguration zu ändern, wurde der gesamte Datensatz neu ins
Flash programmiert (bzw. bei speziellen Entwicklungsgeräten in ein
eingeblendetes RAM geschrieben).
A. K. schrieb:> Hast du mal nachgesehen, auf welchem Weg bei einem ARM7 (v-N) die> Konstante 3840 üblicherweise in einem Register landet?
Ich hatte mal in die entsprechende Stelle des Backends geschaut; nach >
1000 LOC nur zum Laden von Compiletime-Konstanten (ohne Pools!) hab
ich's dann gelassen ;-)
Hendrik L. schrieb:> Rolf Magnus schrieb:>>> "#define-Konstanten" gibt es nicht. #define macht nur eine Textersetzung>> im Quellcode.>>>> Hallo Rolf,>> das hatten wir nun schon ein paar Mal- ist klar!
Na offenbar ist es das nicht.
> Dennoch kann ich über "#define" Konstanten definieren, die vom Prozessor> als "unveränderlicher Wert" arithmetisch verarbeitet werden! Oder nicht> etwa?!
Sie werden nicht von ihm arithmetisch verarbeitet (außer in
#if-Anweisungen), sondern als Text in den an die nächste Compilerstufe
weitergegebenen Quellcode eingetragen. Der Präprozessor interessiert
sich nicht weiter, was das für Text ist.
Auch das ist korrekter C-Code:
1
#include<stdio.h>
2
3
intmain()
4
{
5
#define X = 3; printf
6
intiX("%d\n",i);
7
return0;
8
}
Sieh den Präprozessor als eine Art simplen Texteditor, der die
Anweisungen zur Bearbeitung des Textes aus dem Text selbst erhält.
Wenn du
1
#define MY_CONSTANT 3
schreibst, ist das annähernd das gleiche, als ob du in deinem Editor,
mit dem du deinen Quellcode schreibst, die
"Suchen-und-Ersetzen"-Funktion nutzt, um alle Vorkommen von MY_CONSTANT
durch 3 zu ersetzen.
> Ich schlage vor, wir schliessen diesen Thread - sonst findet ein Newbie> die Kernaussage,>> daß die "#define-Konstante" via Präprozessor im Hex Code landet und> daher nicht adressierbar ist,
Der Präprozessor hat nichts mit dem Hex-Code am Hut. Der macht seine
Ersetzung im C-Code.