Ponteiros de function e endereço de uma function

Então eu percebi que ao fazer pointers de function, você não precisa do operator & para obter o endereço da function inicial:

 #include  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; } 

saída:

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

Então eu percebi que isso também é verdade para matrizes, o que significa que se você tiver int a[10] tanto a quanto &a ponto para o mesmo local. Por que isso acontece com arrays e funções? O endereço é salvo em um local de memory que tenha o mesmo endereço que o valor (endereço) que está sendo salvo nele?

Dado int a[10] , ambos a e &a produzem o mesmo endereço, sim, mas seus tipos são diferentes.

a é do tipo int[10] . Quando é implicitamente convertido em um tipo de ponteiro, o ponteiro é do tipo int* e aponta para o elemento inicial da matriz. &a é do tipo int (*)[10] (isto é, um ponteiro para uma matriz de dez inteiros). Como não pode haver preenchimento em uma matriz, ambos produzem pointers com o mesmo valor , mas os pointers têm tipos diferentes.

As funções são semelhantes às matrizes, mas não são totalmente iguais. Sua function foo é do tipo double(double) . Sempre que foo é usado em uma expressão e não é o operando do operador unário & , ele é implicitamente convertido em um ponteiro para si mesmo, que é do tipo double(*)(double) .

Assim, para todos os efeitos práticos, o nome de uma function e um ponteiro para a mesma function são intercambiáveis. Existem algumas sutilezas, todas as quais eu discuto em uma resposta para “Por que todas essas definições de ponteiro de function maluca funcionam? O que realmente está acontecendo?” (Essa pergunta foi feita sobre o C ++, mas as regras para funções não-membros em C ++ são as mesmas que para as funções em C.)

Não, não há armazenamento extra dedicado a apontar para a function / matriz.

Com a maioria das variables variable_name tem um significado diferente de obter o endereço dessa variável, então você precisa usar &variable para obter o endereço.

Com uma function ou matriz, function_name (por si só, não seguido por parênteses) não tem nenhum outro significado, então não houve problema em interpretá-lo como o endereço da function.

Da mesma forma em sentido inverso: um ponteiro normal precisa ser desreferenciado explicitamente, mas um ponteiro para uma function não (novamente, porque não há outra interpretação razoável), portanto, é dado um ponteiro para uma function como:

 int (*func)(param_list); 

Os seguintes são equivalentes entre si – ambos chamam qualquer function func points em:

 (*func)(params); func(params); 

Basicamente, como o nome da function é “conhecido” como uma function, o & não é estritamente necessário. Esse comportamento é o mesmo para matrizes. Lembre-se de que uma function em si não é uma variável, portanto, ela se comporta de maneira um pouco diferente do que você poderia esperar às vezes. Se você tiver a 2ª edição do K & R, você pode verificar a seção 5.11 nos pointers para funções, ou o manual de referência no final,

Seção A7.1 Geração de ponteiro: Se o tipo de uma expressão ou subexpressão for “matriz de T” para algum tipo T, o valor da expressão será um ponteiro para o primeiro object na matriz e o tipo da expressão será alterado para “ponteiro para T.” Esta conversão não ocorre da expressão é o operando do unário & operador, … Da mesma forma, uma expressão do tipo “function retornando T”, exceto quando usado como o operando do operador &, é convertido para “ponteiro para function retornando T. ”

Seção A7.4.2 Operador de Endereço: O operador unário & recebe o endereço de seu operando …. O resultado é um ponteiro para o object ou function referenciada pelo lvalue. Se o tipo do operando for T, o tipo do resultado será “ponteiro para T.”

Tanto quanto eu sei, isso é o mesmo para C99.

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

Aqui você está chamando foo passando Ponteiro de Função com pass by value e

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

Aqui você está chamando &foo passando function Ponteiro com pass by reference

em ambos os casos, você está chamando o printf com o ponteiro de function.

Lembre-se foo si é o function pointer value e `não uma variável.

O mesmo acontece com o array. int arr[10] traduz em um bloco contínuo de 10 inteiros e o endereço do primeiro elemento é armazenado em arr. então arr é também um ponteiro.

fun e &fun são exatamente os mesmos (exceto que sizeof (f) é ilegal). a e &a são os mesmos até a aritmética do ponteiro: a + 10 == &a + 1 , porque 10*sizeof(*a) == sizeof(a) (onde sizeof(*a) == sizeof(int) ).