web-dev-qa-db-ger.com

Funktionszeiger und Adresse einer Funktion

Also dachte ich mir, wenn ich Funktionszeiger mache, brauchst du nicht das operator & um die Adresse der Ausgangsfunktion 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;
}

ausgabe:

>./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, was bedeutet, dass wenn Sie int a[10] sowohl a als auch &a auf den gleichen Ort zeigen. Warum ist das mit Arrays und Funktionen? Wird die Adresse an einem Speicherort gespeichert, an dem dieselbe Adresse wie der Wert (die Adresse) gespeichert ist?

47
GradGuy

Bei int a[10] Haben sowohl a als auch &a Dieselbe Adresse, aber ihre Typen sind unterschiedlich.

a ist vom Typ int[10]. Wenn der Zeiger implizit in einen Zeigertyp konvertiert wird, hat er den Typ int* Und zeigt auf das ursprüngliche Element des Arrays. &a Ist vom Typ int (*)[10] (dh ein Zeiger auf ein Array von zehn Ganzzahlen). Da es in einem Array keine Auffüllung geben kann, ergeben beide Zeiger mit demselben Wert , aber die Zeiger haben unterschiedliche Typen .

Funktionen ähneln Arrays, sind aber nicht ganz gleich. Ihre Funktion foo ist vom Typ double(double). Immer wenn foo in einem Ausdruck verwendet wird und nicht der Operand des unären Operators & Ist, wird er implizit in einen Zeiger auf sich selbst konvertiert, der vom Typ double(*)(double) ist.

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

66
James McNellis

Nein, es gibt keinen zusätzlichen Speicher, der auf die Funktion/das Array verweist.

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

Mit einer Funktion oder einem Array kann function_name (für sich genommen, ohne Klammern) hat keine andere Bedeutung, sodass es kein Problem gab, 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 (auch hier gibt es keine andere vernünftige Interpretation). Geben Sie daher einen Zeiger auf eine Funktion wie:

int (*func)(param_list);

Die folgenden sind einander äquivalent - beide rufen die Funktion func auf, auf die sie zeigen:

(*func)(params);

func(params);
8
Jerry Coffin

Grundsätzlich ist das & nicht unbedingt erforderlich, da der Funktionsname als Funktion "bekannt" ist. Dieses Verhalten gilt auch für Arrays. Denken Sie daran, dass eine Funktion selbst keine Variable ist und sich daher ein wenig anders verhält, als Sie es manchmal erwarten. Wenn Sie über die 2. Ausgabe von K & R verfügen, lesen Sie Abschnitt 5.11 zu Hinweisen auf Funktionen oder das Referenzhandbuch am Ende.

Abschnitt A7.1 Zeigergenerierung: Wenn der Typ eines Ausdrucks oder Unterausdrucks für einen Typ T "Array von T" ist, 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 Konvertierung findet nicht statt, da der Ausdruck der Operand des unären & -Operators ist. Ebenso wird ein Ausdruck vom Typ "function returning T", außer wenn er als Operand des & -Operators verwendet wird, in "pointer to" konvertiert 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 Wert verweist. Wenn der Typ des Operanden T ist, ist der Typ des Ergebnisses "Zeiger auf T."

Soweit ich weiß, gilt dies auch für C99.

1
Cameron

fun und &fun sind genau gleich (außer dass sizeof (f) illegal ist). a und &a sind bis zur Zeigerarithmetik gleich: a + 10 == &a + 1, weil 10*sizeof(*a) == sizeof(a) (where sizeof(*a) == sizeof(int)).

1
Loic

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

Hier rufen Sie foo auf, indem Sie den Funktionszeiger mit pass by value Und übergeben

printf ("fun2 =% p\tfoo =% p\n", fun2 & foo)

Hier rufen Sie &foo Auf, indem Sie die Funktion Pointer mit pass by reference Übergeben.

in beiden Fällen rufen Sie das printf nur mit Funktionszeiger auf.

Denken Sie daran, dass foo selbst function pointer value Und keine Variable ist.

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

0
rahul maindargi