2013-10-27 7 views
8

Ich habe diese beiden Testfunktionen:Warum sind beide Funktionszeiger in C/C++ zulässig?

int apply_a(int (*fun)(int, int), int m, int n) { 
    return (*fun)(m,n); 
} 

int apply_b(int (*fun)(int, int), int m, int n) { 
    return fun(m,n); 
} 

sie scheinen etwas anderes zurück, also warum beide liefern das gleiche Ergebnis?

int add(int a, int b) {return a + b;} 

int res_a = apply_a(add, 2, 3); // returns 5 
int res_b = apply_b(add, 2, 3); // returns 5 

Ich hätte angenommen, dass einer von ihnen die Zeigeradresse oder den Zeiger selbst zurückgeben würde; anstatt der Wert, der auf dem Zeiger gespeichert wird ...

Also warum macht es das?

+2

Da entweder Syntax (mit oder ohne Sternchen) ist gültig für eine Funktion über einen Zeiger aufgerufen wird. Der zweite Fall ist ein Aufruf (Sie können an den Klammern erkennen und Parameter übergeben). – StoryTeller

+10

Weder ist gut. Sie sollten '(*** fun) (m, n)' verwenden, um sich als Drei-Sterne-Programmierer zu qualifizieren. –

Antwort

7

Weil C++ syntaktischen Zucker bietet, wenn es darum geht, die Adresse von Nichtmitgliedsfunktionen zu handhaben und Zeiger auf sie zu verwenden.

Man kann Adresse dieser Funktion erhalten:

int someFunc(int); 

mit entweder:

int (* someFuncPtr)(int) = someFunc; 

oder:

int (* someFuncPtr)(int) = &someFunc; 

Es für die Verwendung solcher Zeiger auch syntaktischer Zucker ist, entweder Anruf Zeigefunktion mit:

(*someFuncPtr)(5); 

oder mit vereinfachten Syntax:

someFuncPtr(5); 
+0

Denken Sie daran, dass das gleiche gilt auch für statische Klassenmethoden (zumindest auf Visual C++ 2012, wo ich überprüft habe;)) – altariste

+0

gilt das auch in C? oder ist die Zuckerregel nur für C++? –

+0

C++ führt eine andere Notation für den Typ "function" ein: 'int (int)', die in 'int (*) (int) 'konvertierbar ist. 'someFunc' hat den Typ' int (int) ', während' & someFunc' den Typ 'int (*) (int)' hat. –

0

in C und C++ Namen von Funktionen sind ebenfalls die Zeiger auf den Funktionscode. Wie jeder Zeiger können Sie sie mithilfe von * dereferenzieren, was im Fall von Funktionszeigern den Aufruf der Funktion bedeutet, wenn zusätzlich zur Dereferenzierung auch eine Paranthese nach ihnen verwendet wird, wie in Ihrem Fall apply_a. Aber auch ein gültiger Aufruf der C- und C++ - Funktion ruft sie einfach nach ihrem Namen auf, nämlich apply_b.

+0

Es ist nicht der Name. ** Jeder ** Ausdruck, der eine Funktion ist, nicht nur ein Funktionsname, wird in einen Zeiger auf die Funktion umgewandelt. –

1

Dies liegt daran, dass Sie keine Speicheradressen dieser Werte zurückgeben. Der Aufruf einer Funktion mit Zeiger ändert ihren Wert nicht, sie ruft immer noch die Funktion auf. Was Sie tun können, ist ein Wert einer Variablen zurückgeben und dann bekommen es ist Speicheradresse wie:

int result = fun(m,n); 
cout << "the result " << result << " pointing at " << &result << endl; 
6

(*fun)(m,n) die gleiche ist wie fun(m,n) aufgrund Regeln in C und C++, die Funktionen Zeiger auf Funktionen konvertieren.

In C 2011 ist die Regel Klausel 6.3.2.1 4: "A Funktion Bezeichner ist ein Ausdruck, der Funktionstyp hat. Außer wenn es der Operand des Operators sizeof ist, die _Alignof Operator oder unäre & Operator, eine Funktion Bezeichner mit dem Typ „Funktion Typ zurückkehr“ wird in einen Ausdruck umgewandelt dieses Typs „Zeiger hat Funktion zurück Typ ". In C++ ist die Regel Klausel 4.3.

Beachten Sie, dass ein Funktionsbezeichner nicht nur ein Bezeichner ist, der eine Funktion benennt.Es könnte eine Kennung sein, oder es könnte ein anderer Ausdruck sein. Wenn beispielsweise foo der Name einer Funktion ist, wird sie automatisch in einen Zeiger auf eine Funktion umgewandelt. Dann, da foo ein Zeiger auf die Funktion ist, ist *foo die Funktion. Das heißt, Sie schreiben:

(*fun)(m,n) 

Das Ergebnis ist, dass fun automatisch in einen Zeiger umgewandelt wird, dann * auf die Funktion ausgewertet wird, dann wird *fun in einen Zeiger umgewandelt zurück, dann wird die Funktion aufgerufen. Sie können dies auch weiterhin und schreiben:

(**************fun)(m,n) 

Dies ist die gleiche wie fun(m,n) ist. Jedes * erzeugt die Funktion erneut, aber der Compiler konvertiert es automatisch zurück in einen Zeiger. Du kannst diese Schlacht für immer fortsetzen, aber der Compiler wird immer gewinnen.

In der Tat, diese alle den gleichen Effekt haben:

(&fun)(m,n) 
(fun)(m,n) 
(*fun)(m,n) 
Verwandte Themen