2009-06-03 2 views
1

Ich habe eine seltsame typedef-Anweisung in einem C++ - Programm, generiert von Py ++.Wie kann der Zeiger auf eine Funktion ohne Dereferenzierung aufgerufen werden?

double radius(int); // function to be wrapped 
typedef double (*radius_function_type)(int);  
bp::def("radius", radius_function_type(&radius)); // bp::def is a function for wrapping 

Was dachte ich, ist so weit aus, dass der oben typedef statemnt nicht von der Art ist, die meisten von uns sind vertraut mit,

typedef complex_type simple_alias; 

Vielmehr ist es ein Weg, Zeiger auf eine Funktion zu deklarieren welches int als Argument nimmt und doppelt zurückgibt (wie der Prototyp). Also meine Frage ist nun, wie kommt Zeiger auf eine Funktion (ohne Dereferenzierung)genannt mit Adresse einer Funktion als Argument? Dies passt auch nicht zum Prototyp. Jemand bitte erklären!

Antwort

3

Ihre Frage ist verwirrend.Sind Sie fragen, was das bedeutet:

radius_function_type(&radius)" 

Dies ist nur ein C++ Typumwandlung, ein bisschen wie:

radius (int (42)); 

aber da Radius bereits vom Typ radius_function_type ist, dann können Sie genauso einfach tun:

bp::def("radius", radius); 

aber da dies Code ist, der von Py ++ erzeugt wird, ist es wahrscheinlich besonders vorsichtig mit der Ausgabe.

+1

eher wie eine C-Stil Typumwandlung, eigentlich. C++ hat static_cast, dynamic_cast usw. – crashmstr

+0

Beachten Sie auch (ich denke), dass der Grund für diese Cast-Syntax die Kompatibilität mit Konstruktoren ist (insbesondere im Template-Code). So ruft MyClass (0) einen 1-arg-Konstruktor von MyClass, float (0) den gleichen Wert wie 0.0 und radius_function_type (0) den Nullzeiger auf double (*) (int). float (0), my_type (0) sind gleichbedeutend mit (float) 0, (my_type) 0. –

+2

Es ist in der Tat keine Typumwandlung im C-Stil. C verwendet ausschließlich die Form (TYPE) EXPR. In C++ können Sie auch TYPE (EXPR) verwenden. Der vorherige Kommentar stellt korrekt fest, dass dies die Ctor-Form von Casting ist und Ctors offensichtlich eindeutig für C++ sind. – MSalters

2

Nun ... Es ist ein bisschen ähnlich, wie Arrays mit Zeigern in C und C++ verwandt sind. Der Name einer Funktion ist im Grunde auch ein Zeiger. Unter diesem Gesichtspunkt ist es nicht allzu überraschend, dass eine Definition gegeben:

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

Sie können den Anruf tun, entweder direkt, durch den Zeiger, der den Namen der Funktion lautet:

foo(1, 2); 

oder durch diesen Wert zu speichern in einer separaten Variable, die als Zeiger deklariert werden müssen:

int (*pointer)(int, int) = foo; 
pointer(1, 2); 

in diesem Fall können wir durch die Zeigervariable direkt anrufen, und es gibt auch keine Notwendigkeit, explizit „nehmen die Adresse "der Funktion durch Schreiben &foo.

+0

Ich schätze Ihre schnelle Antwort sehr. Was aber noch nicht erklärt wurde, ist, dass das Argument in Radius_Funktionstyp (& Radius) die Adresse einer Funktion ist, die nicht mit dem Prototyp übereinstimmt. Bitte werfen Sie etwas Licht auf dieses Problem! – Aamir

+1

@Aamir: & Radius und Radius dienen beide als Zeiger auf die Funktion. Da Funktionen in C++ keine erstklassigen Objekte sind, gibt es keine Möglichkeit, eine andere Funktion als einen Zeiger darauf zu verwenden, und so können Sie mit der Sprache genau das tun, was Sie wollen. Dieses Verhalten für Funktionsnamen steht im Gegensatz zu Variablen: Wenn Sie global eine Ganzzahl my_int deklarieren, sind my_int und & my_int völlig unterschiedliche Dinge. –

1

Dereferenzieren (auf die Art und Weise, wie Sie denken) den Zeiger einer Funktion bedeutet: Zugriff auf einen CODE-Speicher, wie es ein DATA-Speicher wäre.

Der Funktionszeiger darf auf diese Weise nicht dereferenziert werden. Stattdessen heißt es.

Ich würde einen Namen "dereference" Seite an Seite mit "Anruf" verwenden. Es ist in Ordnung.

Wie auch immer: C ist so ausgelegt, dass sowohl der Name des Funktionsnamens als auch der Zeiger der Variablenhaltefunktion dasselbe bedeuten: Adresse CODE-Speicher. Und es ermöglicht, zu diesem Speicher zu springen, indem Sie die call() -Syntax entweder für einen Bezeichner oder eine Variable verwenden.

6

Es deklariert keine Funktionszeigervariable, sondern einen Funktionszeiger typedef namens radius_function_type. radius_function_type(&radius) ist nur eine (redundante) Umwandlung für den Funktionszeiger selbst. (Die unären & Adressoperator ist auch überflüssig, für eine Funktion, radius und &radius sind dasselbe.)

auf niedrigem Niveau, den Aufruf einer Funktion nur gemäß den Argumenten irgendwo platziert auf die Aufrufkonvention zugrunde liegen (normalerweise auf dem Stapel) und dann zu einer Speicheradresse springen. So kann der Compiler eine Funktion nur mit einem Zeiger aufrufen, wenn er den Funktionszeigertyp (Funktionssignatur) und den Zeigerwert selbst kennt.

1

Der Funktionszeiger ist im Grunde die Adresse der Funktion, die aufgerufen werden muss. Um die Funktion aufzurufen, auf die ein Funktionszeiger zeigt, betrachten Sie den Funktionszeiger als den Namen der Funktion, die Sie aufrufen möchten. Der Akt, es selbst zu nennen, führt die Dereferenzierung durch; es besteht keine Notwendigkeit für eine explizite Dereferenzierung.

Funktionszeiger-Syntax kann wie Zeiger (mit & und *) aussehen oder auch weggelassen werden. Wie schon @unwind gezeigt, ist es ähnlich wie Arrays behandelt werden, wo bare Array ähnlich wie Zeiger ist und optional können Sie das Array mit & voranstellen, um die Adresse zu erhalten.

+0

Danke. Eine viel hilfreiche Erklärung – Aamir

+1

Sie machen einen gemeinsamen Fehler über Arrays: gegeben 'int n [100]', & n * ist nicht * das gleiche wie n (n ist konvertierbar zu int *, & n ist nicht) –

Verwandte Themen