Возможно ли / безопасно / вменяемо передать указатель на функцию в статическую функцию? - PullRequest
10 голосов
/ 28 февраля 2011

Допустим, я хочу открыть функцию только из одного из моих файлов, передав указатель на эту функцию. Безопасно ли объявлять эту функцию как 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 из другого файла?

Ответы [ 5 ]

11 голосов
/ 28 февраля 2011

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

3 голосов
/ 28 февраля 2011

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

Вот пример:

$ 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!
$ 

Сложная часть заключается в получении объявления функции, принимающей указатель на функцию, возвращающую voidправый.

1 голос
/ 28 февраля 2011

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


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

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

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

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

1 голос
/ 28 февраля 2011

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

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

1 голос
/ 28 февраля 2011

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

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

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

...