Rendre la fonction visible uniquement dans une bibliothèque, pas dans l'API

Nov 29 2020

J'écris une bibliothèque C99 qui est distribuée entre plusieurs fichiers, par exemple

// core.h
void my_private_fn();

void API_my_public_fn();
// core.c
#include "core.h"

void my_private_fn() {
    do_something();
}

void API_my_public_fn() {
    do_something_else();
}
// module_a.h
#include "core.h"

void API_useful_thing();
// module_a.c
#include "module_a.h"

void API_useful_thing() {
    my_private_fn();
}

Je veux que les API_fonctions préfixées soient visibles par un programme utilisant la bibliothèque, mais je dois aussi exposer my_private_fndans core.hafin d'être utilisé par module_a.c. Existe-t-il un moyen en C de my_private_fnne rendre visible que dans la bibliothèque?

Réponses

3 SergeBallesta Nov 29 2020 at 01:39

Si la fonction ne devait être visible que dans l'unité de compilation où elle est définie, vous pouvez la déclarer static. Parce que le langage C offre peu de portées possibles: un symbole ne peut avoir que 3 portées:

  • local à un bloc (le bloc peut être une fonction ou un bloc à l'intérieur d'une fonction)
  • portée statique (déclaration statique en dehors d'une fonction): le symbole n'est visible que dans l'unité de compilation où il est déclaré
  • portée globale (déclaration non statique en dehors d'une fonction): le symbole est visible dans tout le programme.

Tout au plus, vous pouvez masquer la déclaration dans un fichier d'inclusion privé que vous ne déclarez pas dans l'API documentée officielle. De cette façon, les utilisateurs obéissants ne devraient pas l'utiliser. Mais vous ne pouvez pas empêcher les utilisateurs de mettre la déclaration dans leur propre code et d'utiliser la fonction.

2 JohnKugelman Nov 29 2020 at 01:35

Placez-les dans un fichier d'en-tête interne qui n'est utilisé qu'à l'intérieur de la bibliothèque et non distribué aux utilisateurs finaux, par exemple core_internal.h.

user3758232 Dec 31 2020 at 00:19

J'ai trouvé un moyen plus soigné de présenter mon code en me basant sur la réponse de Serge que j'ai choisie, dont le plus grand mérite revient.

La clé est de mettre les fonctions "privées" dans des en-têtes qui ne sont inclus que dans les fichiers C, pas dans les fichiers d'en-tête. De cette façon, les symboles «privés» sont disponibles en interne mais pas à un appelant externe. Dans un exemple complet:

core.h:

void my_public_fn();

core_priv.h:

void my_private_fn();

core.c:

#include <stdio.h>

#include "core.h"
#include "core_priv.h"

void my_private_fn() {
    printf("Private function called.\n");
}

void my_public_fn() {
    printf("Public function called.\n");
}

module_a.h:

#include "core.h"

void module_a_fn();

module_a.c:

#include "core_priv.h"
#include "module_a.h"

void module_a_fn() {
    my_private_fn();
    my_public_fn();
}

Et si nous le voulons, nous pouvons regrouper éventuellement plusieurs modules dans un en-tête de bibliothèque commun.

library.h:

#include "module_a.h"
// etc.

De cette façon, un programme utilisant la bibliothèque n'a besoin d'inclure qu'un seul fichier avec seulement:

main.c:

#include "library.h"

int main() {
    //my_private_fn(); // This triggers a compile warning.
    my_public_fn();    // I can still reach the "core" public function.
    module_a_fn();     // This calls the "private" function internally.

    return 0;
}

Compilation gcc -Wall *.c -o main.oet exécution des ./main.orendements:

Public function called.
Private function called.
Public function called.