Funktionszeiger und Adresse einer Funktion

Lesezeit: 5 Minuten

Benutzeravatar von mmirzadeh
mmirzadeh

Also dachte ich, wenn man Funktionszeiger macht, braucht man das nicht operator & um die Adresse der Anfangsfunktion zu erhalten:

#include <stdio.h>

double foo (double x){
    return x*x;
}

int main () {

    double (*fun1)(double) = &foo;
    double (*fun2)(double) =  foo;

    printf("%f\n",fun1(10));
    printf("%f\n",fun2(10));

    printf("fun1 = %p \t &foo = %p\n",fun1, &foo);
    printf("fun2 = %p \t  foo = %p\n",fun2,  foo);       

    int a[10];

    printf("  a = %p \n &a = %p  \n",a,&a);

    return 0;
}

Ausgang:

>./a.out 
100.000000
100.000000
fun1 = 0x4004f4      &foo = 0x4004f4
fun2 = 0x4004f4       foo = 0x4004f4
  a = 0x7fff26804470 
 &a = 0x7fff26804470 

Dann wurde mir klar, dass dies auch für Arrays gilt, dh wenn Sie haben int a[10] beide a und &a zeigen auf die gleiche Stelle. Warum ist das bei Arrays und Funktionen so? Ist die Adresse an einem Speicherplatz gespeichert, der dieselbe Adresse hat wie der darin gespeicherte Wert (Adresse)?

  • Ich habe nie ganz verstanden, warum Sie nicht den address-of-Operator verwenden mussten, um die Adresse einer Funktion zu übernehmen. Ich bin immer davon ausgegangen, dass das nur ein bisschen syntaktischer Zucker ist.

    – BillRobertson42

    4. März 2012 um 5:48 Uhr

  • @Bill: Genau! Das ist, was ich immer denke, aber es scheint, dass Sie das nicht müssen!

    – mmirzadeh

    4. März 2012 um 5:51 Uhr

  • Wenn die Adresse am selben Speicherplatz wie sie selbst gespeichert wurde, können die eigentlichen Funktionscode/Array-Daten nicht vorhanden sein! Sie behandeln Arrays praktisch als Zeiger und Funktionen, die als Argumente übergeben werden, ebenfalls als Zeiger, sodass Sie den addressof-Operator nicht benötigen. Grundsätzlich ist der ‘Wert’ einer Funktion oder eines Arrays Unsinn. Nur die Adresse macht Sinn, also erhalten Sie das, wenn Sie den “Wert” abfragen, und auch, wenn Sie die Adresse abfragen.

    Benutzer529758

    4. März 2012 um 6:22 Uhr


Benutzeravatar von James McNellis
James McNellis

Gegeben int a[10]beide a und &a dieselbe Adresse liefern, ja, aber ihre Typen sind unterschiedlich.

a ist vom Typ int[10]. Wenn er implizit in einen Zeigertyp konvertiert wird, ist der Zeiger vom Typ int* und zeigt auf das Anfangselement des Arrays. &a ist vom Typ int (*)[10] (d. h. ein Zeiger auf ein Array aus zehn ganzen Zahlen). Da in einem Array kein Padding vorhanden sein kann, ergeben beide Zeiger mit demselben Wert Wertaber die Zeiger haben unterschiedliche Typen.

Funktionen sind Arrays ähnlich, aber nicht ganz gleich. Ihre Funktion foo ist vom Typ double(double). Wann auch immer foo wird in einem Ausdruck verwendet und ist nicht der Operand des unären & -Operator, wird er implizit in einen Zeiger auf sich selbst konvertiert, der vom Typ ist double(*)(double).

Aus praktischen Gründen sind also der Name einer Funktion und ein Zeiger auf dieselbe Funktion austauschbar. Es gibt einige Feinheiten, die ich alle in einer Antwort auf “Warum funktionieren all diese verrückten Definitionen von Funktionszeigern? Was ist wirklich los?” (Diese Frage wurde zu C++ gestellt, aber die Regeln für Nichtmember-Funktionen in C++ sind die gleichen wie für Funktionen in C.)

Nein, es gibt keinen zusätzlichen Speicher, der dafür vorgesehen ist, auf die Funktion/das Array zu zeigen.

Mit den meisten Variablen variable_name hat eine andere Bedeutung als das Abrufen der Adresse dieser Variablen, also müssen Sie verwenden &variable um die Adresse zu bekommen.

Mit einer Funktion oder einem Array function_name (an sich, ohne Klammern) hat keine andere Bedeutung, daher war es kein Problem, es so zu interpretieren, dass es die Adresse der Funktion verwendet.

Ebenso umgekehrt: Ein normaler Zeiger muss explizit dereferenziert werden, ein Zeiger auf eine Funktion jedoch nicht (wiederum, weil es keine andere vernünftige Interpretation gibt). Geben Sie also einen Zeiger auf eine Funktion wie:

int (*func)(param_list);

Die folgenden sind einander äquivalent – beide rufen eine beliebige Funktion auf func Punkte auf:

(*func)(params);

func(params);

  • Es scheint jedoch einen kleinen Unterschied zu geben, für int a[10](*a)[5] ist kein gültiger Anruf

    – mmirzadeh

    4. März 2012 um 6:02 Uhr

Benutzeravatar von Loic
Loic

fun und &fun sind genau gleich (außer dass sizeof(f) illegal ist).
a und &a sind bis auf Zeigerarithmetik gleich: a + 10 == &a + 1Weil 10*sizeof(*a) == sizeof(a) (wo sizeof(*a) == sizeof(int)).

Camerons Benutzeravatar
Cameron

Da bekannt ist, dass es sich bei dem Funktionsnamen um eine Funktion handelt, ist das & nicht unbedingt erforderlich. Dieses Verhalten gilt auch für Arrays. Denken Sie daran, dass eine Funktion selbst keine Variable ist und sich daher etwas anders verhält, als Sie manchmal erwarten. Wenn Sie die 2. Ausgabe von K&R haben, können Sie Abschnitt 5.11 über Verweise auf Funktionen oder das Referenzhandbuch am Ende lesen.

Abschnitt A7.1 Zeigererzeugung: Wenn der Typ eines Ausdrucks oder Unterausdrucks für irgendeinen Typ T „Array von T“ ist, dann ist der Wert des Ausdrucks ein Zeiger auf das erste Objekt im Array, und der Typ des Ausdrucks ist geändert in “Zeiger auf T.” Diese Umwandlung findet nicht statt, wenn der Ausdruck der Operand des unären &-Operators ist, … Ähnlich wird ein Ausdruck vom Typ „Funktion, die T zurückgibt“, außer wenn er als Operand des &-Operators verwendet wird, in „Zeiger auf Funktion, die T zurückgibt.”

Abschnitt A7.4.2 Adressoperator: Der unäre &-Operator nimmt die Adresse seines Operanden…. Das Ergebnis ist ein Zeiger auf das Objekt oder die Funktion, auf die der lvalue verweist. Wenn der Typ des Operanden T ist, ist der Ergebnistyp “Zeiger auf T”.

Soweit ich weiß, ist dies bei C99 genauso.

printf(“fun1 = %p \t &foo = %p\n”,fun1, foo);

Hier rufst du an foo indem Sie den Funktionszeiger mit übergeben pass by value
und

printf(“fun2 = %p \t foo = %p\n”,fun2, &foo)

Hier rufst du an &foo indem Sie die Funktion Pointer with übergeben pass by reference

In beiden Fällen rufen Sie die an printf nur mit Funktionszeiger.

Denken Sie daran foo selbst ist function pointer value und `keine Variable.

Dasselbe passiert mit Array.
int arr[10] übersetzt in einen kontinuierlichen Block von 10 Ganzzahlen und die Adresse des ersten Elements wird in arr gespeichert. also ist arr auch ein Zeiger.

1411880cookie-checkFunktionszeiger und Adresse einer Funktion

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy