Есть ли разница между этими способами получения указателей функций в C?

Я возился с указателями функций и заметил кое-что в следующей программе:

#include <stdio.h>

int operation (int x, int y, int (*fptr)(int, int))
{
        int z;
        z = (*fptr)(x, y);
        return (z);
}
int add(int a, int b) {
        return a+b;
}
int main(int argc, char** argv) {
        /* This line */ printf("%d\n", operation(1, 2, add));
}

Запуск этой программы приводит к 3, как и должно быть.

Однако в строке, отмеченной /* This line */, я заметил, что если строка была изменена на любой из этих двух других вариантов, это также привело к 3: printf("%d\n", operation(1, 2, *add) и printf("%d\n", operation(1, 2, &add) (обратите внимание на добавленные звездочку и амперсанд).

Это также работает, когда я пробовал такие вещи, как printf("%d\n", operation(1, 2, *(&add))); и printf("%d\n", operation(1, 2, &(*add))); (что я предположил, увидев выше).

Мне было интересно, почему это так, и есть ли разница между двумя вариантами. Является ли это неопределенным поведением, и мне просто повезло, предполагает ли компилятор, что все это означает одно и то же, или здесь происходит что-то странное, чего я не понимаю?


person russellsayshi    schedule 14.04.2015    source источник
comment
для указателей функций x и *x одинаковы   -  person M.M    schedule 14.04.2015
comment
Ознакомьтесь с как работает typedef для указателей на функции.   -  person Jonathan Leffler    schedule 14.04.2015


Ответы (2)


Из стандарта ANSI/ISO 9899-1990 C, раздел 6.2.2.1:

Указатель функции – это выражение функционального типа. За исключением случаев, когда это операнд оператора sizeof или унарного оператора &, указатель функции с типом "функция, возвращающая тип" преобразуется в выражение типа "указатель на функцию, возвращающую тип".

Это означает, что add сам по себе преобразуется в указатель. &add также является указателем по определению; Я думаю, именно поэтому это явно исключено из абзаца выше. И *add выполняет двойное преобразование, разыменовывая функцию как указатель, а затем снова интерпретируя ее как указатель.

Я не ожидаю, что будет какая-то разница в скомпилированном коде.

person Mark Ransom    schedule 14.04.2015

На самом деле имена функций — это просто метки для адресов памяти, что делает их держателями адресов наподобие указателей. Таким образом, вы можете думать об именах функций как об указателях. Поэтому неудивительно, что вы можете использовать те же операторы ссылок, что и для указателей.

person Unavailable    schedule 14.04.2015