Как сделать так, чтобы к функции обращались извне?

9

Это специфический для С вопрос. Я пытаюсь сохранить все возможное в границах модуля перевода, раскрывая только несколько функций через .hфайл. То есть я даю staticсвязь с объектами на уровне файлов.

Теперь пара функций должна вызываться другими модулями, но не напрямую. Мой модуль / файл / модуль перевода подписывается на другие модули, передавая указатель на функцию. Затем при конкретном событии указатель вызывается с некоторыми аргументами.

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

  • Должны ли они быть staticили extern(и выставить их в .h)?
  • Должен ли я включить некоторые подсказки в названии функций?
  • Или этого достаточно, чтобы оставить комментарий "под названием X"?
Vorac
источник
1
Это отличный вопрос. Мое решение (которым я не очень доволен, поэтому я просто помещаю это в комментарии) состоит в том, чтобы создать несколько заголовочных файлов с разумным именем и группировать функции в той области, которую я хочу иметь. Для библиотеки AStar, которую я сделал, у меня есть AStar.h, AStar_private.h, AStar_packagePrivate.h и т. Д.
Shivan Dragon

Ответы:

2

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

Поскольку связь в каждой известной реализации CI является символической, все, что вызывает функцию, должно ссылаться на ее символ:

foo();  /* Direct */

some_function_pointer_t funcs[] = { &foo, &bar, &baz };  /* Indirect */

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

Blrfl
источник
1

Итак, я хочу узнать, как сделать так, чтобы эти функции вызывались из какого-то непонятного места.

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

Должны ли они быть статическими или внешними (и выставить их в формате .h)?

static может быть в порядке, если у вас нет классов [-подобных конструкций], которые содержат данные экземпляра.
externозначает, что вы вообще не реализуете это; реализация "приобретается" из других источников в процессе компоновки.

Должен ли я включить некоторые подсказки в названии функций?

Или этого достаточно, чтобы оставить комментарий "под названием X"?

Точно нет.

Такие комментарии, как бы они ни были благонамеренными, устаревают в тот момент, когда вы заканчиваете их писать.

Фил В.
источник
Обращаясь к первому пункту, функции вызываются следующим образом. Мой компонент включает в себя внешний .hфайл. Он вызывает функцию оттуда и дает ей указатель на одну из собственных функций модуля. Позже внешний код вызывает все, что находится по этому указателю. Таким образом, моя функция вызывается кем-то, кто не включает мой заголовочный файл, а я включаю его.
Vorac
1
Что касается второго пункта, насколько я понимаю, объект, определенный в области видимости файла, имеет внешнюю связь по умолчанию; поэтому externключевое слово избыточно` .
Vorac
0

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

lorcap
источник
0

Я все равно сделал бы их static(они не предназначены для того, чтобы быть связанными и вызванными кем-либо), и отмечал бы их назначение как обратные вызовы, предоставляемые внешним функциям от их имени.

static потому что я пытаюсь скрыть то, что могу скрыть, столько, сколько я могу это скрыть.

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

Себастьян Редл
источник
0

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

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

Таким образом, единственная оставленная опция - назвать функцию, чтобы указать, что это обратный вызов. Большинство примеров, которые я видел, используют _callbackлибо _cbкак суффикс, либо cb_как префикс. Используйте длинную форму, если обратные вызовы необычны в вашем коде, короткую форму, если они распространены.

Джонатан Джидди
источник