Указатели на функции и адрес функции
Так что я понял, что при создании указателей на функции вам не нужно 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 ответов
Дано int a[10]
, и то и другое a
а также &a
да один и тот же адрес, да, но их типы разные.
a
имеет тип int[10]
, Когда он неявно преобразуется в тип указателя, указатель имеет тип int*
и указывает на начальный элемент массива. &a
имеет тип int (*)[10]
(то есть указатель на массив из десяти целых чисел). Поскольку в массиве не может быть заполнения, они оба дают указатели с одинаковым значением, но указатели имеют разные типы.
Функции похожи на массивы, но не полностью одинаковы. Ваша функция foo
имеет тип double(double)
, Всякий раз, когда foo
используется в выражении и не является операндом унарного &
оператор, он неявно преобразуется в указатель на себя, который имеет тип double(*)(double)
,
Таким образом, для практических целей имя функции и указатель на одну и ту же функцию взаимозаменяемы. Есть некоторые тонкости, которые я обсуждаю в ответе на вопрос: "Почему все эти безумные определения указателей на функции все работают? Что на самом деле происходит?" (Этот вопрос был задан о C++, но правила для функций, не являющихся членами в C++, такие же, как и для функций в C.)
Нет, нет дополнительной памяти, предназначенной для указания на функцию / массив.
С большинством переменных variable_name
имеет значение, отличное от получения адреса этой переменной, поэтому вам нужно использовать &variable
чтобы получить адрес.
С функцией или массивом, function_name
(само по себе, не сопровождаемое круглыми скобками) не имеет никакого другого значения, поэтому не было проблем с его интерпретацией как получение адреса функции.
Аналогично в обратном порядке: нормальный указатель должен явно разыменовываться, но указатель на функцию - нет (опять же, потому что другой разумной интерпретации нет), поэтому указатель указывается на такую функцию:
int (*func)(param_list);
Следующее эквивалентно друг другу - оба вызывают любую функцию func
указывает на:
(*func)(params);
func(params);
По сути, поскольку имя функции "известно" как функция, & не является строго обязательным. Это поведение одинаково для массивов. Напомним, что сама функция не является переменной, поэтому она ведет себя немного иначе, чем вы могли бы иногда ожидать. Если у вас есть 2-е издание K&R, вы можете проверить раздел 5.11 по указателям на функции или справочное руководство в конце,
Раздел A7.1 Генерация указателя: если тип выражения или подвыражения является "массивом T" для некоторого типа T, то значением выражения является указатель на первый объект в массиве, а тип выражения - изменено на "указатель на T." Это преобразование не происходит, если выражение является операндом унарного оператора &,... Аналогично, выражение типа "функция, возвращающая T", за исключением случаев, когда оно используется в качестве операнда оператора &, преобразуется в "указатель на функция, возвращающая T. "
Раздел A7.4.2 Оператор адреса: унарный оператор & получает адрес своего операнда.... Результатом является указатель на объект или функцию, на которые ссылается lvalue. Если тип операнда T, тип результата - "указатель на T".
Насколько я знаю, это то же самое для C99.
fun
а также &fun
точно такие же (за исключением того, что sizeof(f) является недопустимым).a
а также &a
одинаковы с точностью до арифметики указателя: a + 10 == &a + 1
, так как 10*sizeof(*a) == sizeof(a)
(где sizeof(*a) == sizeof(int)
).
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 также является указателем.