Как работает оператор typedef для указателя на функцию

Я думаю, что я могу страдать от страшной болезни "случайного программиста", по крайней мере, когда дело доходит до typedefs и указателей функций. Поэтому я экспериментировал со всевозможными комбинациями, включающими их, чтобы проанализировать результаты, основанные на всех выходных данных, которые я получаю.

но поскольку я продолжал пробовать разные комбинации, вместо анализа результатов я теперь просто потерялся в процессе.

Я надеюсь, что вы, ребята, поможете мне разобраться в этом беспорядок.

первый пример кода

typedef void (print)(void);
void do_something (void) { printf("Hello Worldn"); }

print *pr;
pr = &do_something;
pr(); // Hello World

второй пример кода

typedef void (print)(void);
void do_something (void) { printf("Hello Worldn"); }

print *pr;
pr = do_something;
pr(); // Hello World

как работают оба вышеприведенных примера кода, как будто " & " не влияет на имя функции

третий пример кода

typedef void (print)(void);
void do_something (void) { printf("Hello Worldn"); }

print pr;
pr = do_something; // compile error
pr = &do_something; // compile error
pr();

Я надеялся, что одно из вышеупомянутых заданий будет работать здесь, но черт! Я действительно не понимаю указателей функций (и, возможно, typedef тоже).

4 ответов


адрес имени функции и простое имя функции означают одно и то же, поэтому & не влияет на имя функции.

аналогично, при использовании указателей функций многократное разыменование не является проблемой:

#include <stdio.h>
typedef void print(void);
static void dosomething(void) { printf("Hello World\n"); }

int main(void)
{
    print *f1 = dosomething;
    print *f2 = &dosomething;
    f2();
    (f1)();
    (*f1)();
    (**f2)();
    (***f1)();
    (****f2)();
    (*****f1)();
}

что компилируется в:

gcc -O3 -g -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
    -Wold-style-definition -std=c99 xx.c -o xx

Я бы не стал утверждать, что несколько звезд-это хороший стиль-это не так. Это странно, и (да, вы можете сказать это) порочные'. Одного достаточно (и одна звезда в основном для таких людей, как я, кто научился программировать на C до стандарта, сказал: "нормально вызывать функцию с помощью указателя без использования (*pointer_to_function)(arg1, arg2) нотации; вы можете просто написать pointer_to_function(arg1, arg2) если вам нравится"). Да, это странно. Нет, ни один другой тип (или класс типов) не проявляет такого же поведения, слава богу.


дело в указателях функций заключается в том, что они являются функцией указатели! : -) вот как вы получаете свой третий образец для работы:

#include <stdio.h>
typedef void (*print)(void);
//            ^
void do_something (void) { printf("Hello World\n"); }
int main (void) {
    print pr;
    pr = do_something; // &do_something would also work.
    pr();
    return 0;
}

С точки зрения того, используете ли вы funcName или &funcName, это не имеет значения (по крайней мере, в C). Раздел 6.3.2.1 Lvalues, arrays and function designators гласит:

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


оказывается, что в C/C++ оба funcname и &funcname даст адрес funcname и может быть присвоена переменной указателя функции. На самом деле это просто странность того, как синтаксис был разработан для языка(языков).


как и C, C++ имеет указатель на функции: указатель на функцию, которая не принимает аргументов и не возвращает значения. Однако C++ также ввел ссылки на функции void (&)() и между ними есть неявные преобразования (хотя я точно не помню правила).

таким образом:

  • funcname является ссылкой на функцию
  • &funcname - указатель на функцию

обратите внимание, что принимать адрес (или ссылка на) перегруженной функции требует static_cast к точному типу (разрешить перегрузку).