Comment rendre évident qu'une fonction est accessible de l'extérieur?


9

Il s'agit d'une question spécifique C. J'essaie de garder tout ce qui est possible à l'intérieur des limites de l'unité de traduction, en exposant seulement quelques fonctions à travers le .hfichier. Autrement dit, je donne un staticlien vers des objets de niveau fichier.

Maintenant, quelques fonctions doivent être appelées par d'autres modules, mais pas directement. Mon module / fichier / unité de traduction s'abonne aux autres modules, en passant un pointeur sur une fonction. Ensuite, lors d'un événement spécifique, le pointeur est appelé avec quelques arguments.

Je me demande donc comment rendre très évident que ces fonctions sont appelées depuis un endroit obscur.

  • Doivent-ils être staticou extern(et les exposer dans le .h)?
  • Dois-je inclure un indice dans le nom des fonctions?
  • Ou suffit-il de mettre un commentaire "appelé par X"?

1
Voilà une excellente question. Ma solution (avec laquelle je ne suis pas du tout trop content, c'est pourquoi je ne le mets que dans un commentaire) est de créer plusieurs fichiers d'en-tête, judicieusement nommés, et de regrouper les fonctions sur l'étendue que je veux qu'ils aient. Pour la bibliothèque AStar que j'ai créée, j'ai AStar.h, AStar_private.h, AStar_packagePrivate.h, etc ...
Shivan Dragon

Réponses:


2

Du point de vue de l'unité de compilation (fichier), la seule chose à laquelle vous devez vous préoccuper est de savoir si la fonction est disponible ou non à l'extérieur. Le rendre disponible signifie qu'il était destiné à être appelé, et vous devez opérer en supposant que ces appels auront lieu. Votre préoccupation avec la fonction elle-même commence à son point d'entrée. La façon dont le contrôle y parvient en premier lieu n'a d'importance que pour le code qui le rend possible.

Étant donné que le lien dans chaque implémentation de CI connu est symbolique, tout ce qui appelle une fonction doit faire référence à son symbole:

foo();  /* Direct */

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

Si vous déclarez tort foo()d'être static, votre programme ne sera pas un lien. Si vous le déclarez non static, vous avez une fonction exposée qui n'est pas appelée. Les questions sur l'utilisation ou non d'une fonction peuvent être résolues en vidant les tables de symboles de vos fichiers objets ou en les recherchant dans les sources.


1

Je me demande donc comment rendre très évident que ces fonctions sont appelées depuis un endroit obscur.

Définissez «obscur».
Les méthodes doivent être exposées à travers des "interfaces" bien définies et, comme Shivan Dragon l'a déjà suggéré, ces "interfaces" sont vos fichiers .h. Si vous ne donnez pas à un autre programme le "bon" fichier d'en-tête, il ne peut pas appeler la méthode.

Doivent-ils être statiques ou externes (et les exposer dans le .h)?

static peut être OK tant que vous n'avez pas de classe [-constitutions similaires] qui contiennent des données d'instance.
externsignifie que vous ne l'implémentez pas du tout; une implémentation est "acquise" ailleurs pendant le processus de liaison.

Dois-je inclure un indice dans le nom des fonctions?

Ou suffit-il de mettre un commentaire "appelé par X"?

Absolument pas.

Des commentaires comme celui-ci, même s'ils sont bien intentionnés, sont obsolètes au moment où vous avez fini de les écrire.


Pour répondre à votre premier point, les fonctions sont appelées comme suit. Mon composant comprend un .hfichier externe . Il appelle une fonction à partir de là et lui donne un pointeur sur l'une des fonctions du module. Plus tard, le code externe appelle tout ce qui se trouve sur ce pointeur. Ainsi, ma fonction est appelée par quelqu'un qui n'inclut pas mon fichier d'en-tête, j'inclus plutôt le sien.
Vorac du

1
Concernant le deuxième point, autant que je sache, l' objet, défini à la portée du fichier, a un lien externe par défaut; par conséquent, le externmot clé est redondant » .
Vorac

0

Si des fonctions de rappel sont définies dans votre module et que l'utilisateur ne fournira jamais l'une des siennes, je pense que vous pouvez utiliser un espace réservé pendant la phase d'initialisation. L'espace réservé est généralement un enumqui est ensuite traduit en interne dans la bonne staticfonction.


0

Je les ferais toujours static(ils ne sont pas destinés à être liés à et appelés par n'importe qui), et marquerais leur objectif comme des rappels fournis à des fonctions externes en leur nom.

static parce que j'essaie de cacher ce que je peux cacher, autant que je peux le cacher.

Marquez-les dans leur nom, car a), les commentaires sont obsolètes et b), il devient évident à l'endroit où le rappel est fourni que cette fonction est destinée à être utilisée de cette façon: cela en fait essentiellement un drapeau rouge pour prendre l'adresse d'une fonction qui ne respecte pas la convention de dénomination.


0

Les modificateurs de portée doivent être utilisés principalement comme informations pour le compilateur, et non comme une forme de documentation "assez proche". L'utilisation de staticen particulier permet à un compilateur C de rendre la fonction inutilisable de l'extérieur du module, y compris en tant que rappel - pas ce que vous voulez, même si cela peut fonctionner avec votre compilateur actuel.

Bien sûr, vous devez ajouter un commentaire au code, car vous pouvez voir que c'est une situation potentiellement déroutante. Tout ce qui est inhabituel ou inattendu a besoin d'un commentaire approprié. Mais, comme indiqué dans d'autres réponses, les commentaires peuvent ne pas être lus ou devenir obsolètes.

Donc, la seule option qui reste est de nommer la fonction pour indiquer qu'il s'agit d'un rappel. La plupart des exemples que j'ai vus utiliser _callbackou _cbcomme suffixe, ou cb_comme préfixe. Utilisez le formulaire long si les rappels sont inhabituels dans votre code, le formulaire court s'ils sont courants.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.