Forum: Compiler & IDEs Referenzen in C


von Stefan N. (nollsen)


Lesenswert?

Hi,

ist es möglich in C, bei einem Funktionsaufruf die Referenz von einer 
Variable zu übergeben? Muss ich den Compiler dazu auf C++ umstellen, 
oder gibt es im C eine Spezialoption wie ich das bewerkstelligen kann?

In C++ sehen die Referenzen ja ungefähr so aus:


void settest(int& dst)
{
dst = 123;
}

void main(void)
{
int a;
settest(a);
}

in dem normalen C Dialekt (glaube C95 oder so) hat dieses Beispiel nicht 
funktioniert.

klar das könnte man natürlich auch mit pointern lösen:


void settest(int* dst)
{
*dst = 123;
}

void main(void)
{
int a;
settest(&a);
}


aber das was der compiler da herausgeneriert ist nicht schön:

void settest(int* dst)
{
  92:  fc 01         movw  r30, r24
*dst = 123;
  94:  8b e7         ldi  r24, 0x7B  ; 123
  96:  90 e0         ldi  r25, 0x00  ; 0
  98:  91 83         std  Z+1, r25  ; 0x01
  9a:  80 83         st  Z, r24
}
  9c:  08 95         ret

gibts es eine andere möglichkeit für referenzen?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Was ist denn an dem Code nicht schön?
Immerhin ist er optimal so wie er übersetzt wurde.

Referenzen in C++ werden intern ähnlich abgebildet: syntaktischer 
Zucker. Mehr nicht.

von Stefan N. (nollsen)


Lesenswert?

naja,
eigentlich sollten ja referenzen noch besser zu behandeln sein als 
normal übergeben variablen, da die variablen aus der vorherigen funktion 
weiterbenutzt werden können und nicht erst auf dem stack gesichert 
werden müssen oder auf neue register umkopiert.

optimal übersetzt finde ich das ehrlichgesagt nicht, der compiler könnte 
schon merken dass effektiv nur eine konstante speicherstelle angesteuert 
wird...

von Karl H. (kbuchegg)


Lesenswert?

Stefan Noll wrote:

> optimal übersetzt finde ich das ehrlichgesagt nicht, der compiler könnte
> schon merken dass effektiv nur eine konstante speicherstelle angesteuert
> wird...

Du kannst dich ja hinsetzen und für den gcc eine entsprechende 
Datenflussanalyse schreiben, die draufkommt, dass deine Funktion nur ein 
einziges mal aufgerufen wird und daher das dst innerhalb eines 
Programmlaufs immer auf dieselbe Speicherstelle zeigen wird.

Wie du das dann allerdings machen willst, wenn sich Funktion und Aufruf 
in verschiedenen Übersetzungseinheiten befinden bleibt dir überlassen.

Praxisrelevant ist so eine Analyse allerdings nicht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

hmmm selbst wenn man weiß daß die Funktion (statisch) nur 1x gerufen 
wird brnigt das nix, weil man nicht an den Ort des referenzierten 
Objektes kommt.

Wenn du mehr Information über die Funktion hast kannst Du dem Compiler 
das mitteilen, etwa wenn sie nur in einem Modul gebraucht wird (static). 
Vielleicht bringt das schon die Optimierung.

Und hast mal den Code angeschaut, den avr-g++ für eine Referenz macht? 
Ich glaub nicht daß der besser ist als mit Zeigern.

von Peter (Gast)


Lesenswert?

versuche doch mal die Funktion als Inline zu machen. Dann sollte er es 
etwas besser hinbekommen.

Ich kämpfe zur zeit mit ähnlichen Problemen, In C Programmieren ist zwar 
schön aber das was am ende Rauskommt ist leider selten optimal (was die 
optimierung angeht). Der Computer kann halt noch nicht denken.

von yalu (Gast)


Lesenswert?

> optimal übersetzt finde ich das ehrlichgesagt nicht, der compiler
> könnte schon merken dass effektiv nur eine konstante speicherstelle
> angesteuert wird...

Das ist optimal, was der Compiler da macht. Der merkt nämlich noch
viel mehr, nämlich dass der Aufruf der Funktion ohne Effekt ist, und
optimiert ihn deswegen komplett weg. Die Funktion selbst muss er aber
stehen lassen, weil er nicht wissen kann, ob sie vielleicht noch von
einem anderen Modul aufgerufen wird. Da er dieses Modul nicht kennt,
kann er auch keine Annahmen über die Variable machen, deren Adresse als
Argument übergeben wird. Also ist der erzeugte Code in diesem Kontext
perfekt.

Wenn du möchtest, dass der Programmcode von settest ebenfalls
wegoptimiert wird, musst du Johanns Vorschlag folgen und die Funktion
static deklarieren, um dem Compiler anzuzeigen, dass sie nicht von
anderen Modulen aufgerufen wird.

Interessanteres Beispiel: Rufst du nach settest(&a) eine externe
Funktion mit a als Argument auf, kann der Compiler das settest nicht
komplett ignorieren, da der Wert von a ja noch benötigt wird. Aber
selbst dann wird sehr stark optimiert: Der Compiler lässt den Aufruf von
settest ebenfalls weg und schreibt die 123 direkt in die
Argumentübergaberegister.

Kurz: Der GCC optimiert nicht immer perfekt, das ist bekannt. Aber
gerade in dem von dir genannte Beispiel zeigt er in beeindruckendster
Weise seine Fähigkeiten.

Die C++-Referenzen sind, wie Johann geschrieben hat, nur syntaktischer
Zucker. Sie sind sematisch äquivalent mit konstanten Pointern, die
initialisiert werden, denen aber kein Wert zugewiesen werden kann.

von Stefan N. (nollsen)


Lesenswert?

hi,

vielen dank für den tipp mit dem als static deklarieren, erste versuche 
damit sehen schon ganz gut aus.

ich habe kurz zwei varianten ausprobiert,

void dosomethingwith(int a)
{
* ((int*)0) = a;
}

static int settest()
{
  return 123;
}


void main(void)
{
  int a;
  a = settest();
  dosomethingwith(a);
}

einmal mit return und einmal mit übergebenem pointer. beide varianten 
hatten am ende die gleiche übersetzung und der compiler hat beides zu
den einfachen 4 zeilen
  9c:  8b e7         ldi  r24, 0x7B  ; 123
  9e:  90 e0         ldi  r25, 0x00  ; 0
  a0:  90 93 01 00   sts  0x0001, r25
  a4:  80 93 00 00   sts  0x0000, r24
wegoptimiert. also bei mit static deklarierten funktionen merkt er wohl 
wirklich dass es sich nur um eine speicherstelle handelt.

kurz zum hintergrund: ich habe ein programm das einen quelltext 
generieren soll, und da wäre es unpraktisch wenn ich nochmal 
differenzieren müsste ob ein funktionsargument zurückgegeben werden soll 
oder kopiert werden soll.

von yalu (Gast)


Lesenswert?

> vielen dank für den tipp mit dem als static deklarieren […] der
> compiler hat beides zu den einfachen 4 zeilen […] wegoptimiert.

Den Funktionsaufruf wegoptimiert hätte er auch ohne das static. Das
static bewirkt aber zusätzlich, dass die damit nicht mehr benötigte
Funktion selbst ebenfalls weggelassen wird, was keine Rechenzeit, aber
Programmspeicher spart. Deswegen ist es sinnvoll, alle Funktionen (und
auch alle globalen Variablen), die nur in einem einzelnen Modul
verwendet werden, als static zu deklarieren, zumal das Programm dadurch
auch durchschaubarer wird.

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.