Указатели на функции и адрес функции - PullRequest
46 голосов
/ 04 марта 2012

Итак, я подумал, что при создании указателей на функции вам не нужно operator &, чтобы получить адрес исходной функции:

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

вывод:

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

Тогда японял, что это также верно для массивов, то есть, если у вас int a[10], то и a, и &a указывают на одно и то же местоположение.Почему это с массивами и функциями?Сохранен ли адрес в ячейке памяти, адрес которой совпадает с адресом, в котором хранится значение (адрес)?

Ответы [ 5 ]

66 голосов
/ 04 марта 2012

Учитывая int a[10], оба a и &a дают один и тот же адрес, да, но их типы различны.

a имеет тип int[10].Когда он неявно преобразуется в тип указателя, указатель имеет тип int* и указывает на начальный элемент массива.&a имеет тип int (*)[10] (то есть указатель на массив из десяти целых чисел).Поскольку в массиве не может быть заполнения, они оба дают указатели с одинаковым значением , но указатели имеют разные типы .

Функции аналогичны массивам,но не совсем то же самое.Ваша функция foo имеет тип double(double).Всякий раз, когда foo используется в выражении и не является операндом унарного оператора &, он неявно преобразуется в указатель на себя, который имеет тип double(*)(double).

Итак, для всехВ практических целях имя функции и указатель на одну и ту же функцию взаимозаменяемы.Есть некоторые тонкости, которые я обсуждаю в ответе «Почему все эти сумасшедшие определения указателей на функции работают? Что происходит на самом деле?» (Этот вопрос был задан о C ++, но правиладля функций, не являющихся членами в C ++, такие же, как для функций в C.)

8 голосов
/ 04 марта 2012

Нет, нет дополнительной памяти, предназначенной для указания на функцию / массив.

Для большинства переменных variable_name имеет значение, отличное от получения адреса этой переменной, поэтому вам нужно использовать &variable для получения адреса.

С функцией или массивом, function_name (само по себе, без скобок) не имеет никакого другого значения, поэтому не было проблем с интерпретацией его как получения адреса функции.

Аналогично в обратном порядке: нормальный указатель должен явно разыменовываться, но указатель на функцию - нет (опять же, потому что нет другой разумной интерпретации), поэтому дан указатель на функцию, подобную:

int (*func)(param_list);

Следующие элементы эквивалентны друг другу - обе они вызывают любую функцию, func указывает на:

(*func)(params);

func(params);
1 голос
/ 01 апреля 2015

fun и &fun абсолютно одинаковы (за исключением того, что sizeof (f) недопустим).a и &a одинаковы с точностью до арифметики указателя: a + 10 == &a + 1, потому что 10*sizeof(*a) == sizeof(a) (где sizeof(*a) == sizeof(int)).

1 голос
/ 04 марта 2012

По сути, поскольку имя функции «известно» как функция, & не является строго обязательным.Это поведение одинаково для массивов.Напомним, что сама функция не является переменной, поэтому она ведет себя немного иначе, чем вы могли бы иногда ожидать.Если у вас есть 2-е издание K & R, вы можете проверить раздел 5.11 по указателям на функции или справочное руководство в конце,

Раздел A7.1 Генерация указателей: Если тип выраженияили подвыражение является «массивом T» для некоторого типа T, тогда значение выражения является указателем на первый объект в массиве, а тип выражения изменяется на «указатель на T».Это преобразование не происходит, если выражение является операндом унарного оператора &, ... Аналогично, выражение типа «функция, возвращающая T», за исключением случаев, когда оно используется в качестве операнда оператора &, преобразуется в «указатель нафункция, возвращающая T. "

Раздел A7.4.2 Оператор адреса: унарный оператор & получает адрес своего операнда .... Результатом является указатель на объект или функцию, на которые ссылается lvalue.Если тип операнда T, тип результата - «указатель на T».

Насколько я знаю, это то же самое для C99.

0 голосов
/ 22 апреля 2013

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

Здесь вы звоните foo, передав Функциональный указатель с pass by value и

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

Здесь вы вызываете &foo, передав функцию Pointer с помощью pass by reference

в обоих случаях вы вызываете printf только с указателем на функцию.

Помните, foo само по себе является function pointer value и `не является переменной.

То же самое происходит с массивом. int arr[10] преобразуется в непрерывный блок get из 10 целых чисел, а адрес первого элемента сохраняется в обр. таким образом, arr также является указателем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...