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

Так что я понял, что при создании указателей на функции вам не нужно 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 также является указателем.

Другие вопросы по тегам