Forum: Compiler & IDEs Parameterübergabe bei Funktionen: by reference


von Oliver R. (rendgeor)


Lesenswert?

Hallo,
warum kann ich bei Verwendung des gcc-avr die Parameter nicht als 
Referenz übergeben?

void AddOne(int& y);

void AddOne(int& y)
{
    y++;
}


-->
main.c:27: error: expected ';', ',' or ')' before '&' token

von A. H. (Gast)


Lesenswert?

Falscher Operator ?
Mit einem int* (es ist ja ein Zeiger) funktioniert es besser.

Du kannst das Argument ja nicht dereferenzieren, nicht in der 
Definition.

von Oliver R. (rendgeor)


Lesenswert?

Nein,
es existieren in c sowohl & und * Typen.
Pointer!=Referenz
Referenz ist etwas sauberer & abgesicherter.

Bsp aus:
http://www.learncpp.com/cpp-tutorial/73-passing-arguments-by-reference/

von Jörg G. (joergderxte)


Lesenswert?

Du meinst 'in C++', das ist eine andere Sprache...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Eben. C kennt keine Referenzen.

von Rolf M. (rmagnus)


Lesenswert?

Oliver Rendgen schrieb:
> es existieren in c sowohl & und * Typen.

Nein.

> Pointer!=Referenz

Richtig, und C != C++.

> http://www.learncpp.com/cpp-tutorial/73-passing-ar...

Überschrift: "Tutorials to help you master C++ ...".

Es gibt aber auch avr-g++. Da geht das. Aber "abgesicherter" ist da 
deshalb noch nix.

von Klaus W. (mfgkw)


Lesenswert?

Oliver Rendgen schrieb:
> Nein,
> es existieren in c sowohl & und * Typen.

nein, wie bereits gesagt - solange es um C geht.

> Pointer!=Referenz

Richtig.

> Referenz ist etwas sauberer & abgesicherter.

Wieso das?
Zeiger deklarieren und die Adresse übergeben ist genauso
sauber und nur eine andere Schreibweise wie eine Referenz.
Irgendwie abgesichert sind beide nicht im Mindesten.
Wenn du den Zeiger in der Funktion nicht versehentlich
ändern möchtest, kannst du ihn eleganterweise als const
deklarieren.
Ab dann ist es nur noch eine Ausdrucksweise für eine Referenz.

von Simon B. (nomis)


Lesenswert?

Klaus Wachtler schrieb:
> Oliver Rendgen schrieb:
>> Referenz ist etwas sauberer & abgesicherter.
>
> Wieso das?
> Zeiger deklarieren und die Adresse übergeben ist genauso
> sauber und nur eine andere Schreibweise wie eine Referenz.
> Irgendwie abgesichert sind beide nicht im Mindesten.

Jain. Referenzen kann man AFAIK nur von existierenden Variablen bilden, 
insbesonders kann man keinen NULL-Pointer übergeben...

... was natürlich ein Problem ist, weil man dann keinen bequemen 
Mechanismus hat um z.B. die Abwesenheit eines Parameters zu 
signalisieren...

Viele Grüße,
        Simon

von Klaus W. (mfgkw)


Lesenswert?

Simon Budig schrieb:
> Referenzen kann man AFAIK nur von existierenden Variablen bilden
1
class A
2
{
3
public:
4
  A()
5
    : wert(*new int)
6
  {
7
  }
8
9
  ~A()
10
  {
11
    delete &wert;
12
  }
13
14
private:
15
  int &wert;
16
};

Und wehe du behauptest, das wäre kein richtiges C++!

von Rolf M. (rmagnus)


Lesenswert?

Simon Budig schrieb:

>> Irgendwie abgesichert sind beide nicht im Mindesten.
>
> Jain. Referenzen kann man AFAIK nur von existierenden Variablen bilden,

Weder das, noch ist nach Anlegen der Referenz gesichert, daß die 
Variable auch noch existiert, wenn man die Refernz dann benutzen will.

> insbesonders kann man keinen NULL-Pointer übergeben...

Man darf nicht, weil es keine NULL-Referenzen gibt. Daß es nicht 
passiert, dafür muß man aber immer noch selbst sorgen:
1
int* p = 0;
2
AddOne(*p);

Zugegebenermaßen liegt hier nach C++-Norm das Problem schon bei der 
Dereferenzierung beim Aufruf, aber effektiv läuft es bei allen mir 
bekannten Compilern darauf hinaus, daß innerhalb der aufgerufenen 
Funktion dasselbe geschieht, wie bei einer Funktion, die einen Zeiger 
erwartet und NULL übergeben bekommt.

> ... was natürlich ein Problem ist, weil man dann keinen bequemen
> Mechanismus hat um z.B. die Abwesenheit eines Parameters zu
> signalisieren...

Naja, das kann man auch gerade als Mittel einsetzen, also die Referenz 
gerade dann verwenden, wenn man ganz klar will, daß der Parameter nicht 
weggelassen werden kann.

von Peter (Gast)


Lesenswert?

Simon Budig schrieb:
> Jain. Referenzen kann man AFAIK nur von existierenden Variablen bilden,
> insbesonders kann man keinen NULL-Pointer übergeben...

doch kann man, es ist möglich einen Referenz auf NULL zu übergeben. Aber 
üblich ist es bestimmt nicht.

von Rolf M. (rmagnus)


Lesenswert?

Peter schrieb:
> es ist möglich einen Referenz auf NULL zu übergeben. Aber üblich ist es
> bestimmt nicht.

Nein, möglich ist das eigentlich nicht. Man kann Code so schreiben, daß 
es in der Praxis darauf hinausläuft, aber offiziell ist schon die 
Erzeugung einer Referenz auf NULL nicht möglich, bzw. der Versuch hat 
undefiniertes Verhalten.

von Simon B. (nomis)


Lesenswert?

Vorweg: Wir bewegen uns hier natürlich im Language-Lawyer-Land und ich 
bin kein C++-Experte, weil ich es meide, wo ich nur kann. Irgendwie 
steigern die von Euch gebrachten Beispiele auch nicht gerade meine 
Sympathie für C++   :-)

Rolf Magnus schrieb:
> Man darf nicht, weil es keine NULL-Referenzen gibt. Daß es nicht
> passiert, dafür muß man aber immer noch selbst sorgen:
> int* p = 0;
> AddOne(*p);

Hust. Das ist ja mal hässlich...  :-)

Ok, man kann kaputte Referenzen übergeben, aber auch nur, indem man eine 
Variable im Sourcecode hinschreibt. Einfach nur AddOne (NULL); geht 
nicht - was vom Sourcecode her natürlich die deutlich klarere Variante 
wäre...

Peter schrieb:
> doch kann man, es ist möglich einen Referrenz auf NULL zu übergeben. Aber
> üblich ist es bestimmt nicht.

Ja Moment, es ist aber ein Unterschied, ob Du eine Referenz auf einen 
Nullpointer (also eine Speicheradresse in der NULL drinsteht) übergibst, 
oder ob Du einen Nullpointer übergibst. Zumindest auf einer logischen 
Ebene - was ein Compiler draus macht ist nochmal eine andere Sache, s.o.

Viele Grüße,
        Simon

von Karl H. (kbuchegg)


Lesenswert?

Simon Budig schrieb:

> bin kein C++-Experte, weil ich es meide, wo ich nur kann. Irgendwie
> steigern die von Euch gebrachten Beispiele auch nicht gerade meine
> Sympathie für C++   :-)

Lass dich davon nicht verwirren.
In der Praxis ist DIESER Punkt weit weniger ein Problem, als es jetzt 
scheint.

>> int* p = 0;
>> AddOne(*p);
>
> Hust. Das ist ja mal hässlich...  :-)

Es ist das Standardbeispiel in den Newsgroup, mit der jemand beweisen 
will, dass er eine NULL-Referenz erzeugen kann. Nur übersieht er dabei 
leider, dass sein Fehler streng genommen schon beim *p steckt und die 
Referenz nichts dafür kann.


> Variable im Sourcecode hinschreibt. Einfach nur AddOne (NULL); geht
> nicht - was vom Sourcecode her natürlich die deutlich klarere Variante
> wäre...

Niemand hindert dich

   AddOn( *NULL );

zu schreiben. :-)
(Ist natürlich genauso falsch)

> Ja Moment, es ist aber ein Unterschied, ob Du eine Referenz auf einen
> Nullpointer (also eine Speicheradresse in der NULL drinsteht) übergibst,
> oder ob Du einen Nullpointer übergibst. Zumindest auf einer logischen
> Ebene - was ein Compiler draus macht ist nochmal eine andere Sache, s.o.

Referenzen werden in C++ gerne misverstanden.
Offiziell ist eine Referenz 'ein anderer Name für ein ansonsten 
existierendes Objekt'. Nicht mehr und nicht weniger. Ob der Compiler das 
mit einem Pointer realisiert oder nicht, ist dem Compiler überlassen. Er 
kann, aber er muss nicht (und in diesem speziellen Fall wird er das mit 
einem Pointer machen)

Referenzen sind in C++ an dieser Stelle insofern praktisch, weil eine 
Funktion damit signalisieren kann: An dieser Stelle will ich vom 
Aufrufer ein Objekt haben. Ich lege es nichgt selbst an, sondern du 
musst es mir übergeben.

Die Fehler von Neulingen sind legendär, in denen sie zb schreiben

  char * result;
  GetString( result );

Auf Nachfrage, warum sie da einen Pointer reinstopfen kommt dann 
meistens:
"
Ja aber die Funktion sieht doch so aus

  void GetString( char * result );

Da steh doch, dass ich der Funktion einen Pointer übergeben soll!
"

Dann muss man erst einmal lang und breit erklären, dass ein Pointer in 
einer Argumentliste 2 Dinge anzeigen kann. Unter anderem auch, dass die 
Funktion vom Aufrufer erwartet, dass er den Speicher bereitstellt und 
die Adresse bekannt gibt an der die Funktion schreiben kann.

Referenzen sind da etwas eindeutiger.

Das ist das eine. Zum anderen ermöglichen Referenzen dem Compiler ein 
paar Optimierungen und für Operator Overloading sind sie sowieso 
notwendig. Die übliche Empfehlung in C++ ist: Verwende lieber Referenzen 
anstelle von Pointern. Pointer in einer Argumentliste nur dann, wenn es 
die Möglichkeit geben soll, dass der Aufrufer signalisiern kann "Ich hab 
hier nichts was ich dir geben könnte" oder "Interessiert mich nicht"

Aber wie gesagt: Lass dich davon nicht irre machen. Refernzen sind in 
C++ noch das harmloseste und in der Praxis auch kein größeres Problem 
als NULL-Pointer in C. Hat man das erst mal im Griff, wundert man sich 
was denn die ganze Zeit daran so schwer erschienen ist.

von Oliver R. (rendgeor)


Lesenswert?

Danke Allen für die Erklärungen,
jetzt weiss ich dass es Referenzen erst mit C++ gab;)

von Klaus W. (mfgkw)


Lesenswert?

Zugegebenermaßen hätte die Diskussion etwas kompakter ausfallen können 
:-)

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.