Entwickler-Ecke
Off Topic - Zu C: Funktion mit/ohne Klammern
GuaAck - Mi 06.05.15 22:19
Titel: Zu C: Funktion mit/ohne Klammern
Liebe C-Experten,
wenn ich wüsste, nach welchem Stichwort ich suchen soll, dann würde ich nicht fragen, schon der Betreff viel mir schwer. Ich bin Pascaler und muss nur gelegentlich und behelfsweise ein paar Zeilen C-Code machen.
Also:
Ich deklarierere eine Funktion und will diese dann aufrufen:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| void Reduzieren() { ... }
void Machewas() { ... Reduzieren; ... } |
Mein Compiler ist zufrieden, aber die Funktion "Reduzieren" wird nicht durchlaufen. Ich muss schreiben "Reduzieren()", dann geht es. Ist das eine Macke meines C-Compilers oder falls nicht, was ist der Sinn, dass er es erlaubt? Hat mich jedenfalls Stunden gekostet, den Fehler zu finden.
Kein Problem mehr, aber ich würde es gerne verstehen.
Gruß Guaack
Stundenplan - Mi 06.05.15 22:52
Ein Methodenname allein ist in C-Sprachen meist nur der Bezeichner für diese Methode, aber noch kein Aufruf. Wenn du die Methode Reduzieren als Parameter übergeben wölltest, sähe das so aus: MyMethod(Reduzieren);
Oder eine Variablenzuweisung: myVar = Reduzieren;
Um den potentiellen Rückgabewert von Reduzieren zuzuweisen, müsstest du myVar = Reduzieren(); schreiben.
Ein Aufruf hingegen verlangt in C-Sprachen immer die Klammern, auch wenn die Parameterliste leer ist.
Somit ist immer eindeutig, ob du einen Methodenaufruf oder einfach nur die Methode selbst meinst.
C# - Mi 06.05.15 22:55
Hey,
der Compiler macht da nix falsch. In C sind Methodennamen Pointer. Wenn du also
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| void Reduzieren() { ... }
void Machewas() { ... Reduzieren; ... } |
schreibst, ohne die Klammern dran zu hängen, wird eine Kopie des Pointers - der auf Reduzieren zeigt - erstellt und gleich wieder verworfen, das ist legal in C.
Das hat den Grund, dass du bei manchen Funktionen Funktionszeiger als Argument übergeben kannst. Ein Beispiel (in C++, C bin ich mir nicht sicher) wäre Multithreading. Dort wird die Funktion selbst als Argument übergeben:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| #include <thread>
using namespace std;
void TuWas(int wert) { ... }
void main() { thread t(TuWas, 4); } |
In C ist es z.B. auch legal sowas zu schreiben:
a wird ausgewertet und das Ergebnis gleich wieder verworfen.
// EDIT
War wohl zu langsam :mrgreen:
// EDIT 2
Hab nochmal nachgeschaut, thread wird erst ab C++ 11 unterstützt. Aber als Beispiel sollte es trotzdem taugen.
Ralf Jansen - Mi 06.05.15 23:06
Zitat: |
a wird ausgewertet und das Ergebnis gleich wieder verworfen. |
Wobei das eine exclusive Eigenschaft von c/c++. Die Compiler jeder anderen c-artige Sprache (die ich kenne) haben dazu gelernt und würden merken das der Ausdruck weder eine Zuweisung noch ein Aufruf ist und das ablehnen. Eine Methode als Typ darf dort nur Teil einer Zuweisung sein (rechte Seite) oder als Parameter eines Methodenaufrufs dienen.
mandras - Mi 06.05.15 23:09
> der Compiler macht da nix falsch. In C sind Methodennamen Pointer.
Das ist die Sache.
In C ist fast alles ein Ausdruck, dessen Ergebnis nicht zwangsläufig verwendet werden muß.
Wenn Du schreibst
MachWas;
liefert das die Adresse der Funktion MacheWas. Und die wird nicht verwendet - also ignoriert.
Wenn Du schreibst
MachWas ();
Wird die Funktion aufgerufen, weil () der Funktionsaufrufoperator ist - er bekommt das was links von ihm steht und was innerhalb der Klammern ist.
Was in den Klammern ist "wertet er aus" und übergibt diese Daten an die Funktion, deren Adresse er weiß weil der Name links von ihm steht.
Ist eben ein anderes Denkmodell als bei Pascal.
Allerdings können in neueren Delphi-Versionen Funktionen nicht nur mittels Machwas sondern auch per MachWas() aufgerufen werden wenn sie keine Parameter erwarten - wurde wohl eingeführt um ein bischen C-Like zu ermöglichen.
Exkurs:
In C ist auch folgendes möglich:
A=B=C=0;
Abgearbeitet wird es als: A=(B=(C=0)))
"=" ist der Zuweisungsoperator. Vereinfacht gesagt bekommt er die Speicheradresse von C (links von ihm) geliefert und den Wert 0 (rechts). Also schreibt er den Wert 0 an die Speicherstelle an der die Variable C ist.
Als Ergebnis liefert der Zuweisungsoperator den zuzuweisenden Wert (also 0).
Deshalb wird B auch die 0 zugewiesen, ebenso A.
C# - Mi 06.05.15 23:31
Zitat: |
Exkurs:
In C ist auch folgendes möglich:
A=B=C=0; |
Das geht auch in C#
mandras - Mi 06.05.15 23:32
Das geht auch in C#
Davon ging ich aus
GuaAck - Do 07.05.15 22:18
Danke an alle, alle Beiträge haben mir für ein Verständnis genützt.
Die überraschend intensive Diskussion dazu hat mich überrascht - ist wohl jeder mal in die Falle getappt. Ein Kollege gab mir vorhin den Tipp, dass man bei vielen Compilern als Option "Alle Warnungen" einstellen kann, werde ich mal suchen.
Danke nochmals,
GuaAck
mandras - Do 07.05.15 23:47
> Die überraschend intensive Diskussion dazu hat mich überrascht
na, so intensiv war das doch gar nicht
> dass man bei vielen Compilern als Option "Alle Warnungen" einstellen kann, werde ich mal suchen.
Meine letzen echten Erfahrungen mit C liegen 20 Jahre zurück. Soweit ich aber weiß,
hat diese Option auch damals schon gewarnt und war hilfreich.
Eins fällt mir aber noch ein wenn Du als Pascaler Dich in C-Gefilde verirren mußt:
Sei vorsichtig bei Sachen folgender Art:
if (a=5)
{
.. mach nochwas
}
Wie ich oben schon schrieb, in C ist fast alles ein Ausdruck:
"=" ist der Zuweisungsoperator.
Also: a=5 weist der Variablen a den Wert 5 zu. Das IF bekommt das Ergebnis 5. Dies ist ungleich 0 und damit immer wahr.
Gemeint ist eigentlich immer:
if (a == 5) ..
Einstellbare Warnungen des Compilers schreien hier korrekt.
Oftmals wird geraten derartige Vergleiche immer in der Form:
if (5==a)
zu schreiben. Wenn man sich nämlich vertut und nur "=" schreibt gibt es einen echten Fehler : man kann den Wert von a nicht der Konstanten 5 zuweisen.
Weiter oben schrieb Ralf Jansen daß dies exklusive Eigenschaft von C/C++ Compilern sei.
Aufgrund der Abstammung von PHP haben wir dort aber auch fast alle Probleme der Herkunft geerbt, auch wenn PHP interpretieret.
Geprüft habe ich es jetzt nicht, es kann sein, daß PHP bei "machwas;" meckert. bei "if (a=5)" tut es das jedoch nicht..
LG
jfheins - Sa 09.05.15 22:31
Mit dem clang-Compiler bekommst du übrigens folgende Warnung:
Zitat: |
8 : warning: expression result unused [-Wunused-value]
test;
^~~~ |
Davon abgesehen kompiliert C-Code eigentlich "zu leicht" - gewisse Fehler äußern sich dann eben doch erst zur Laufzeit. Ich habe schonmal in C++ versucht, ein 2D-Array mit Arr[2,3] zu indizieren. Hat auch compiliert. Macht aber nicht das, was es soll. :roll:
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!