Има ли разлика между тези начини за получаване на указатели на функции в 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