Возможно ли /safe/sane передать указатель функции на статическую функцию?

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

Не мой код, но (глупый) пример того, что я имею в виду:

void    static   cool_function(void);
void    extern (*cool_function_ptr)(void); // Actually, I’m not sure of where the `extern` goes in a function-
                                           // pointer declaration. Damn you, confusing function-pointer syntax!

Учитывая этот код (или его синтаксически правильное приближение), было бы незаконным доступ к cool_function_ptr из другого файла?

Ответ 1

Это абсолютно безопасно, и часто полезно. То же самое относится к переменным static и указателям данных. Если компилятор хочет делать какие-либо причудливые оптимизации (например, нестандартные соглашения о вызовах, встраивание, рефакторинг и т.д.), Которые могут помешать возможности вызова функции через указатель функции из другой единицы перевода, ответственность компилятора либо определяет, что адрес функции никогда не берется или не генерирует несколько версий кода, один из которых безопасен для вызова извне с помощью стандартного соглашения о вызове.

Ответ 2

Конечно. Указатель функции - это просто адрес, в нем нет ничего волшебного.

Вот пример:

$ cat Makefile
.PHONY: all
all:    main
        ./main
main:   main.c other.c 
        gcc -o main main.c other.c 
$ cat main.c
#include <stdio.h>

static void goodnight(){
  printf("Goonight, gracie!\n");
  return;
}

int
main(char * argv[], int argc){
  other(goodnight);
  return 0;
}
$ cat other.c
#include <stdio.h>

void other(void(*fp)()){
  fp();
  return ;
}
$ make
gcc -o main main.c other.c 
./main
Goonight, gracie!
$ 

Жесткая часть получает объявление функции, переводящей указатель на функцию return void right.

Ответ 3

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

Выполнение этого рода не позволяет вызывающему абоненту узнать полную подпись, поэтому вы играете с огнем и надеетесь, что все выстроится.

И это "extern void" и "static void" - класс хранения, затем тип возврата.

Ответ 4

Нет ничего особенного в указателе на статическую функцию.

Однако, передача указателя вокруг может быть немного менее эффективной, чем позволить ему вызываться напрямую. Мне было непонятно, почему вы это делаете, но это не имело для меня большого смысла.

Ответ 5

Определенно допустимый, потенциально совершенно разумный


Язык позволяет передавать указатель на статическую функцию вне модуля.

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

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

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