Forum: Compiler & IDEs Wie die Adresse einer "#define - Konstanten" ermitteln?


von Hendrik L. (lbd)


Lesenswert?

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.

von g457 (Gast)


Lesenswert?

> 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

von Hendrik L. (lbd)


Lesenswert?

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!

von g457 (Gast)


Lesenswert?

Kein Problem in Pseudocode:
1
#define Konstante 0x027
2
3
void foo(const unsigned long* pulBar);
4
5
6
void main ()
7
{
8
   const unsigned long ulBar = Konstante;
9
   printf ("Addr von ulBar = %p\n", &ulBar);
10
   foo(&ulBar);
11
   ...
12
}

HTH

von Sina A. (sinapse)


Lesenswert?

nachdem der präprozessor ueber
1
vdptr = (long unsigned int *) &Konstante;
läuft kommt das raus
1
vdptr = (long unsigned int *) &0x027;

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

von Hendrik L. (lbd)


Lesenswert?

g457 schrieb:
> Kein Problem in Pseudocode:
>
> [code]
....
>
> HTH

Vielen Dank für die schnelle Antwort.

von Hendrik L. (lbd)


Lesenswert?

Sina Anargo schrieb:
> nachdem der präprozessor ueber
>
1
> vdptr = (long unsigned int *) &Konstante;
2
>
> läuft kommt das raus
>
1
> vdptr = (long unsigned int *) &0x027;
2
>
>
> 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!

von Ulli (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@ 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!

von Hendrik L. (lbd)


Lesenswert?

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?

von Ulli (Gast)


Lesenswert?

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).

von Sina A. (sinapse)


Lesenswert?

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

von Hendrik L. (lbd)


Lesenswert?

Ok - Danke!

Jetzt ist es mir klar!

von Heinz V. (heinz_v)


Lesenswert?

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

von Wolfgang S. (ws01)


Lesenswert?

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
int n;
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.

von Hendrik L. (lbd)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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
void main ()
4
{
5
   vdptr = (long unsigned int *) &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?

von Hendrik L. (lbd)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

Hendrik L. schrieb:
> Harvard-Architektur

Mit Harvard v. von-Neumann hat das nichts zu tun.

von Peter (Gast)


Lesenswert?

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.

von Markus F. (mfro)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Hendrik L. (lbd)


Lesenswert?

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

von Hendrik L. (lbd)


Lesenswert?

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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ü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).

von Peter D. (peda)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

: Bearbeitet durch User
von DJ T. (Gast)


Lesenswert?

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...

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


Lesenswert?

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. ;-)

: Bearbeitet durch Moderator
von (prx) A. K. (prx)


Lesenswert?

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.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von DJ T. (Gast)


Lesenswert?

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).

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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 ;-)

von Rolf M. (rmagnus)


Lesenswert?

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
int main()
4
{
5
    #define X = 3; printf
6
    int i X ("%d\n", i);
7
    return 0;
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.

: Bearbeitet durch User
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.