J'ai donc pensé que lors de la création de pointeurs de fonction, vous n'avez pas besoin du operator &
pour obtenir l'adresse de la fonction initiale:
#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;
}
sortie:
>./a.out
100.000000
100.000000
fun1 = 0x4004f4 &foo = 0x4004f4
fun2 = 0x4004f4 foo = 0x4004f4
a = 0x7fff26804470
&a = 0x7fff26804470
Ensuite, j'ai réalisé que cela est également vrai pour les tableaux, ce qui signifie que si vous avez int a[10]
les deux a
et &a
pointe vers le même emplacement. Pourquoi cela avec des tableaux et des fonctions? L'adresse est-elle enregistrée dans un emplacement mémoire qui a la même adresse que la valeur (adresse) qui y est enregistrée?
Étant donné int a[10]
, a
et &a
Renvoient la même adresse, oui, mais leurs types sont différents.
a
est de type int[10]
. Lorsqu'il est implicitement converti en type de pointeur, le pointeur est de type int*
Et pointe vers l'élément initial du tableau. &a
Est de type int (*)[10]
(c'est-à-dire un pointeur vers un tableau de dix entiers). Parce qu'il ne peut y avoir de remplissage dans un tableau, ils produisent tous deux des pointeurs avec la même valeur , mais les pointeurs ont des valeurs différentes types .
Les fonctions sont similaires aux tableaux, mais pas entièrement identiques. Votre fonction foo
est de type double(double)
. Chaque fois que foo
est utilisé dans une expression et n'est pas l'opérande de l'opérateur unaire &
, Il est implicitement converti en un pointeur sur lui-même, qui est de type double(*)(double)
.
Ainsi, à toutes fins pratiques, le nom d'une fonction et un pointeur vers la même fonction sont interchangeables. Il y a quelques subtilités, dont je discute toutes dans une réponse à "Pourquoi toutes ces définitions de pointeurs de fonctions folles fonctionnent-elles toutes? Que se passe-t-il vraiment?" (Cette question a été posée à propos de C++, mais le les règles pour les fonctions non membres en C++ sont les mêmes que pour les fonctions en C.)
Non, il n'y a pas de stockage supplémentaire dédié au pointage vers la fonction/tableau.
Avec la plupart des variables variable_name
a une signification autre que l'obtention de l'adresse de cette variable, vous devez donc utiliser &variable
pour obtenir l'adresse.
Avec une fonction ou un tableau, function_name
(en soi, non suivi de parenthèses) n'a pas d'autre sens, donc il n'y avait aucun problème à l'interpréter comme prenant l'adresse de la fonction.
De même en sens inverse: un pointeur normal doit être explicitement déréférencé, mais pas un pointeur vers une fonction (encore une fois, car il n'y a pas d'autre interprétation raisonnable), donc donné un pointeur vers une fonction comme:
int (*func)(param_list);
Les éléments suivants sont équivalents les uns aux autres - les deux appellent la fonction que func
pointe vers:
(*func)(params);
func(params);
Fondamentalement, puisque le nom de la fonction est "connu" pour être une fonction, le & n'est pas strictement nécessaire. Ce comportement est le même pour les tableaux. Rappelez-vous qu'une fonction elle-même n'est pas une variable, elle se comporte donc un peu différemment que vous pourriez vous y attendre parfois. Si vous avez la 2e édition de K&R, vous pouvez consulter la section 5.11 sur les pointeurs vers les fonctions, ou le manuel de référence à la fin,
Section A7.1 Génération de pointeur: si le type d'une expression ou d'une sous-expression est "tableau de T" pour un type T, la valeur de l'expression est un pointeur vers le premier objet du tableau et le type de l'expression est modifié en "pointeur vers T." Cette conversion n'a pas lieu de l'expression est l'opérande de l'opérateur unaire &, ... De même, une expression de type "fonction retournant T", sauf lorsqu'elle est utilisée comme l'opérande de l'opérateur &, est convertie en "pointeur vers fonction renvoyant T. "
Section A7.4.2 Opérateur d'adresse: L'opérateur unaire & prend l'adresse de son opérande .... Le résultat est un pointeur vers l'objet ou la fonction référencée par la valeur l. Si le type de l'opérande est T, le type du résultat est "pointeur vers T."
Pour autant que je sache, c'est la même chose pour C99.
fun
et &fun
sont exactement les mêmes (sauf que sizeof (f) est illégal). a
et &a
sont les mêmes jusqu'à l'arithmétique du pointeur: a + 10 == &a + 1
, car 10*sizeof(*a) == sizeof(a)
(où sizeof(*a) == sizeof(int)
).
printf ("fun1 =% p\t & foo =% p\n", fun1, foo);
Ici, vous appelez foo
en passant le pointeur de fonction avec pass by value
et
printf ("fun2 =% p\t foo =% p\n", fun2, & foo)
Ici, vous appelez &foo
en passant la fonction Pointer avec pass by reference
dans les deux cas, vous appelez le printf
avec le pointeur de fonction uniquement.
Rappelez-vous que foo
lui-même est function pointer value
et `pas une variable.
La même chose se produit avec le tableau. int arr[10]
se traduit par obtenir un bloc continu de 10 entiers et l'adresse du premier élément est stockée dans arr. donc arr est aussi un pointeur.