Подтвердить что ты не робот

Указатели функций и адрес функции

Итак, я понял, что при создании указателей функций вам не нужно 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 указывают на одно и то же местоположение. Почему это с массивами и функциями? Является ли адрес сохраненным в ячейке памяти с тем же адресом, что и значение (адрес), сохраненное в нем?

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

int (*func)(param_list);

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

(*func)(params);

func(params);

Ответ 3

В принципе, поскольку имя функции "известно" как функция, оно и не является строго необходимым. Такое поведение одинаково для массивов. Напомним, что сама функция не является переменной, поэтому она ведет себя несколько иначе, чем вы могли бы ожидать иногда. Если у вас есть второе издание K & R, вы можете проверить раздел 5.11 на указатели на функции или справочное руководство в конце,

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

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

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

Ответ 4

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] преобразуется в непрерывный непрерывный блок из 10 целых чисел, а адрес первого элемента сохраняется в arr. поэтому arr также является указателем.

Ответ 5

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