Wie die Adresse einer "#define - Konstanten" ermitteln?

#4123923
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.
#4123941
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
#4123952
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!
#4123955
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!
#4123956
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?
#4123966
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.
#4124009
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
#4124012
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?
#4124020
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
Gast #4124049
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.
#4124054
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.
Persönliche Seite #4124077
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.
#4124095
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
Persönliche Seite #4124122
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).
#4124164
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.
#4124274
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.
Gast #4124299
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...
Moderator Persönliche Seite #4124378
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. ;-)
#4124429
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.
Moderator #4124605
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.
Gast #4124675
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).
#4124987
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren