Forum: Compiler & IDEs reference operator in C?


von Be M. (bemi)


Lesenswert?

Ich würde gerne folgendes machen:
1
  structure f;
2
  structure &ff=f;

In C++ geht das, aber irgendwie will C (WinARM) es nicht akzeptieren.

Was ich will ist eigentlich folgendes.
Ich gehe mal davon aus, dass bei 8-Bit-Mikrocontrollern das Addressieren 
über Pointer von extra Befehlen begleitet wird. Ich stelle mir vor 
(keine Ahnung ob es stimmt), dass wenn ich ein struct an eine feste 
Addresse lege, der Compiler die einzelnen Felder direkt ansprechen kann, 
da die Addresse des Objekts ja fix ist. Also keine Pointeraddressierung.

Nun möchte ich in mehreren Funktion, die ich aufrufe, auf einen 
Speicherbereich zugreifen, der an einer festen Addresse liegt. 
Allerdings wird der Bereich in jeder Funktion unterschiedlich genutzt, 
so dass ich gerne für jede Funktion ein struct deklarieren würde, der 
die Struktur beschreibt.
Meine Frage ist nun, wie sage ich dem C-Compiler, dass die Variable ff 
die Struktur structure hat und fix an Addresse &f im Speicher liegt, so 
dass der Compiler weiß, dass er nicht mit Pointern herumhantieren muss?

von Werner B. (Gast)


Lesenswert?

Aha, Pointerproblem ;)

struct blubb f;
struct blubb *pf = &f;


f.a = 42;
...
if(ff->a == 42) ...

von Be M. (bemi)


Lesenswert?

Genau, und genau das wollte ich vermeiden, da ja bei einem Pointer 
prinzipel das Objekt überall im Speicher liegen könnte. Da mein Objekt 
jedoch an einer festen Stelle liegt, suche ich nach einer Möglichkeit, 
die den Compiler hoffenlich dazu bringt, nicht über Pointerarithmetik 
auf den Speicher zuzugreifen, sondern einfach direkt.

Auch wenn ich derzeit auf einem AVR schreibe, ist es zumindes beim PIC 
so, dass der direkte Zugriff nur einen Zyklus benötigt, während die 
Verwendung von Pointern in etlichen Maschinenbefehlen endet.

von Be M. (bemi)


Lesenswert?

Hier noch mal ein paar Deteils:
62:         ts *s=message+1;
+00000362:   E08D        LDI     R24,0x0D         Load immediate
+00000363:   E091        LDI     R25,0x01         Load immediate
+00000364:   839D        STD     Y+5,R25          Store indirect with 
displacement
+00000365:   838C        STD     Y+4,R24          Store indirect with 
displacement
64:         s->value=3;
+00000366:   81EC        LDD     R30,Y+4          Load indirect with 
displacement
+00000367:   81FD        LDD     R31,Y+5          Load indirect with 
displacement
+00000368:   E083        LDI     R24,0x03         Load immediate
+00000369:   E090        LDI     R25,0x00         Load immediate
+0000036A:   8391        STD     Z+1,R25          Store indirect with 
displacement
+0000036B:   8380        STD     Z+0,R24          Store indirect with 
displacement
65:         s->string[3]='a';
+0000036C:   81EC        LDD     R30,Y+4          Load indirect with 
displacement
+0000036D:   81FD        LDD     R31,Y+5          Load indirect with 
displacement
+0000036E:   E681        LDI     R24,0x61         Load immediate
+0000036F:   8385        STD     Z+5,R24          Store indirect with 
displacement
67:         xx.value=7;
+00000370:   E087        LDI     R24,0x07         Load immediate
+00000371:   E090        LDI     R25,0x00         Load immediate
+00000372:   93900101    STS     0x0101,R25       Store direct to data 
space
+00000374:   93800100    STS     0x0100,R24       Store direct to data 
space
68:         xx.string[3]='a';
+00000376:   E681        LDI     R24,0x61         Load immediate
+00000377:   93800105    STS     0x0105,R24       Store direct to data 
space


Sowohl s als auch xx sind vom type ts. Aber s ist ein pointer. Man 
sieht, dass die Pointervariante deutlich mehr Befehle braucht, obwohl 
'message' fix an einer Konstanten Addresse liegt.

von yalu (Gast)


Lesenswert?

Eine C++-Refernz ist intern nichts anderes als ein Pointer. Der
Unterschied liegt in der Syntax (sie braucht für den Zugriff nicht
dereferenziert zu werden) und in der fehlenden Möglichkeit, ihr einen
Adresswert zuzuweisen (nur eine einmalige Initialisierung ist
möglich).

Daraus ergibt sich, dass sich der für Datenzugriffe über Pointer oder
Referenzen erzeugte Code nicht oder höchstens unwesentlich
unterscheidet.

Nur wenn der Compiler erkennen kann, welche Adresse sich hinter einer
Referenz verbirgt, wird er einen direkten Zugriff auf die Variable
generieren. Das ist bei der Verwendung eines Pointers aber das
Gleiche: Auch dort wird er auf die Derefenzierung verzichten, wenn ihm
klar ist, dass der Pointer nur einen ganz bestimmten Wert annehmen
kann. Ob er diese Optimierung tatsächlich durchführt, kannst du dem
erzeugten Assemblercode entnehmen.

Aber warum möchtest du überhaupt über eine Referenz oder einen Pointer
auf f zugreifen, wenn dieser Pointer sowieso konstant ist? Greift du
direkt auf f zu, wird der Compiler immer den gewünschten optimalen
Code erzeugen.

Zu deinem geposteten Code: Du hast beim Compilieren die Optimierung
nicht eingeschaltet (-O1 oder -O2). Speziell in diesem Beispiel kann
der Compiler nämlich tatsächlich die Dereferenzierung über das
Z-Register wegoptimieren, womit dein Problem vielleicht schon gelöst
ist.

von Karl H. (kbuchegg)


Lesenswert?

Bernd M. wrote:
> Ich würde gerne folgendes machen:
>
1
>   structure f;
2
>   structure &ff=f;
3
>
>
> In C++ geht das, aber irgendwie will C (WinARM) es nicht akzeptieren.

Logisch. C ist nun mal eine andere Sprache als C++.

> Nun möchte ich in mehreren Funktion, die ich aufrufe, auf einen
> Speicherbereich zugreifen, der an einer festen Addresse liegt.
> Allerdings wird der Bereich in jeder Funktion unterschiedlich genutzt,
> so dass ich gerne für jede Funktion ein struct deklarieren würde, der
> die Struktur beschreibt.
> Meine Frage ist nun, wie sage ich dem C-Compiler, dass die Variable ff
> die Struktur structure hat und fix an Addresse &f im Speicher liegt, so
> dass der Compiler weiß, dass er nicht mit Pointern herumhantieren muss?

Fasse die einzelnen Strukturbeschreibungen in eine union zusammen.
1
 struct MyA
2
 { int Mem1; };
3
4
 struct MyB
5
 { double Mem2; };
6
7
 struct MyC
8
 { char Mem3; };
9
10
  union {
11
    struct MyA a;
12
    struct MyB b;
13
    struct MyC c;
14
  } Overlay;
15
16
  Overlay.a.Mem1 = 5;
17
  Overlay.b.Mem2 = 8.0;
18
  Overlay.c.Mem3 = 'a';

Kein Grund zu schmutzigen Tricks zu greifen. Das lässt sich mit
C-Hausmitteln erreichen.

von Be M. (bemi)


Lesenswert?

@yalu:
Stimmt, da das Debugging mit optimiertem Code nicht so richtig wollte, 
habe ich die Optimierung ausgeschaltet. Mit Optimierung macht er 
tatsächlich was ich mir vorstelle. Na ja, mit Pointern kann man auch 
Leben, wenn man mal davon absieht, dass man da immer 2 Zeichen eintippen 
muss :-)

@Karl heinz Buchegger:
Das mit der union habe ich auch schon probiert. Das Problem ist nur, 
dass der Speicher an sich in einer Datei deklariert wird, die von einem 
Code Generator stammt.
Die structs sollen nur dazu dienen, dass man als Benutzer dieses 
generierten Codes nicht mühselig die Datenstruktur wieder 
zusammenstricken muss. Statt dessen einfach ein struct definieren und 
dann so tun, als ob der Datenblock dieser struct wäre.

Grüße,
Bernd

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Bernd M. wrote:
> @yalu:
> Stimmt, da das Debugging mit optimiertem Code nicht so richtig wollte,
> habe ich die Optimierung ausgeschaltet. Mit Optimierung macht er
> tatsächlich was ich mir vorstelle. Na ja, mit Pointern kann man auch
> Leben, wenn man mal davon absieht, dass man da immer 2 Zeichen eintippen
> muss :-)

Es soll da IDEs geben die einem sogar das abnehmen. '.' wird, wenn es 
sich beim rechten Typ um einen Pointer handelt automatisch zu einem -> 
erweitert. Sehr praktisch das.

Matthias

von yalu (Gast)


Lesenswert?

Wenn dass zusätzlich zu tippende Zeichen wirklich stört, kann man sich
ja auch mit einem Makro, das die Dereferenzierung übernimmt, behelfen:
1
structure f;
2
structure pf = &f;
3
4
#define g (*f)
5
6
  pf->a = 123; // Zugriff über Pointer
7
  g.a = 123;   // Alternativ: Zugriff über Makro

Ob das Programm damit wirklich übersichtlicher wird, darf jeder für
sich entscheiden.

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.