web-dev-qa-db-fra.com

Comment implémenter une fonction "privé/restreint" en C?

On m'a posé une question très intéressante lors d'une interview en C: comment implémenter une fonction f() de telle sorte qu'elle ne puisse être appelée qu'à partir d'une fonction g() particulière . Si une fonction autre que g() essaie d'appeler f(), le compilateur générera une erreur.

Au début, je pensais que cela pouvait être fait avec des pointeurs de fonction et que je pouvais presque bloquer l'appel au moment de l'exécution. Mais je n'ai pas été capable de penser à une stratégie de compilation. Je ne sais même pas si cela est possible avec Ansi C.

Est-ce que quelqu'un a une idée?

27
luizleroy

Voici un moyen:

int f_real_name(void)
{
    ...
}

#define f f_real_name
int g(void)
{
    // call f()
}
#undef f

// calling f() now won't work

Une autre façon, si vous pouvez garantir que f() et g() sont les seules fonctions du fichier, consiste à déclarer f() en tant que static.

EDIT: Une autre astuce macro pour provoquer des erreurs de compilation:

static int f(void) // static works for other files
{
    ...
}

int g(void)
{
    // call f()
}
#define f call function

// f() certainly produces compiler errors here
37
Chris Lutz

Placez g() et f() dans le même module et déclarez f() en tant que valeur statique. Le mot-clé static rend f() disponible uniquement pour les fonctions du même module ou du même fichier source.

Vous voudrez peut-être aussi mentionner qu'aucune autre méthode ne devrait être autorisée dans le module avec f() et g (), sinon ils pourraient appeler f ().

PS - Je pense vraiment que la réponse de Chris Lutz est en réalité la meilleure. Il mentionne cette approche, mais aussi un renommage de macro intelligent qui fonctionne avec moins de conditions environnementales (ne nécessite pas le fichier de module spécifiquement pour ces deux fonctions).

Notez également qu'avec une macro, vous pouvez effectuer les opérations suivantes:

#define f() f_should_not_be_called_by_anything_except_g

Ce qui présenterait un message d'erreur Nice, et les auto-complétants (comme Visual Studio) afficheraient ce conseil lorsque l'utilisateur tape f ().

26
Walt W

Vous pouvez créer des fonctions privées du module avec le mot clé static:

static void func(void)
{
    // ...
}

Ensuite, func() ne peut être appelé que par d'autres fonctions définies dans le même fichier (techniquement, la même unité de traduction : d'autres fonctions dont les définitions sont incluses par une directive #include peuvent toujours y accéder). func est réputé avoir un lien interne . Toutes les autres fonctions (c'est-à-dire sans le mot clé static) sont dites avoir external linkage.

Au-delà, non, il n’ya aucun moyen de rendre les fonctions inaccessibles. Vous pouvez utiliser des macros pour modifier le nom de la fonction, mais un autre code peut toujours y accéder avec le nom approprié.

10
Adam Rosenfield

Une option pour GCC consiste à utiliser fonctions imbriquées . Bien que ce ne soit pas la norme C, cela fonctionne assez bien.

8
outis

Placez f() et g() dans le même fichier source, déclarez f() statique.

8
John Millikin

Ce n'est possible que par coïncidence.

Si les fonctions f() et g() se trouvent toutes les deux dans le même fichier source et qu'il n'y a pas d'autres fonctions dans le fichier, et si g()ne retourne jamais le pointeur de fonction sur f() à aucun de ses appelants. Faire alors f() static fera l'affaire.

Si d’autres fonctions doivent figurer dans le même fichier source, placez f() au bas du fichier en tant que fonction statique et définissez uniquement g() immédiatement après le résultat. ou moins le même effet - bien que si vous ne demandiez pas au compilateur de générer des erreurs sur les "déclarations manquantes", d'autres fonctions pourraient l'appeler avec des avertissements.

#include <stdio.h>

extern void g(void);    /* in a header */

/* Other functions that may not call f() go here */

static void f(void)
{
    puts("X");
}

void g(void)
{
    f();
}

Il est clair que cette technique ne peut pas être étendue de manière fiable à une autre paire de fonctions dans le même fichier - x() et y() - telle que x() et seul x() peut appeler y() tandis que g() et seul g() peut appeler f() en même temps.

Cependant, normalement, vous vous fiez à la discipline des programmeurs et créez simplement f() static dans le fichier source, accompagné d'un commentaire que seul g() peut appeler, puis discipline toute personne qui modifie le code de sorte qu'une fonction autre que g() appelle f ().

2
Jonathan Leffler

Tu peux le faire

//some code ...
//You Can't call f() in here - compile time error
//some code ...
void f()
{
    //implement f() in here
}
void g()
{
    //You can only call f() in here - no error
}
#define f() Gimme some ERRORS!!!
//some code ...
//You Can't call f() in here - compile time error
//some code ...
0
Tomer Wolberg