2009-09-09 18 views
22

Me hicieron una pregunta muy interesante durante una entrevista en C: ¿Cómo se puede implementar una función f() de tal manera que solo se puede invocar desde una función g() particular? Si una función distinta de g() intenta llamar a f(), se produciría un error de compilación.¿Cómo implementar una función "privada/restringida" en C?

Al principio, pensé que esto se podía hacer con los punteros a las funciones y que podría acercarme a bloquear la llamada en tiempo de ejecución. Pero no fui capaz de pensar en una estrategia de tiempo de compilación. Ni siquiera sé si esto es posible usando ansi C.

¿Alguien tiene alguna idea?

+0

¿Estás seguro de que la pregunta era exactamente así? No tiene ningún sentido para mí. Quizás si se tratara de funciones miembro, entonces tal vez podría tener algún mérito, ¿pero funciones ordinarias? – Suma

+0

@Suma: No habría funciones miembro en C. –

Respuesta

23

Ponga g() y f() en el mismo módulo, y declare f() como estático. La palabra clave estática hace que f() esté disponible solo para funciones en el mismo módulo o archivo fuente.

Es posible que también desee mencionar que no se deben permitir otros métodos en el módulo con f() y g(), de lo contrario, podrían llamar a f().

PD - Realmente creo que la respuesta de Chris Lutz es en realidad la mejor. Menciona este enfoque, pero también un macroremando inteligente que funciona con menos condiciones ambientales (no requiere el archivo del módulo específicamente para estas dos funciones).

Tenga en cuenta también que, con una macro, puede hacer lo siguiente:

#define f() f_should_not_be_called_by_anything_except_g 

el que se presente un mensaje de error agradable, y concesionarios completers (como Visual Studio) mostraría que la punta cuando el usuario teclea f().

+1

Mira el comentario que hice @John Milikin. – luizleroy

+0

Estoy enterado. Bastante fácil de arreglar sin embargo, realmente. –

+0

En realidad, soy un fan de la respuesta de Jonathan Leffler, pero como dijo no es generalizable. Pero he votado a favor de casi todos los que dijeron la respuesta correcta (es decir, la función "estática"). Probablemente lo que estaban buscando. –

8

Lugar f() y g() en el mismo archivo fuente, declare f() estático.

+1

No creo que esa sea la respuesta esperada. Esto no impide que alguien ponga otras funciones en la misma fuente y cal f(). – luizleroy

+17

Cualquiera que pueda editar su función fuente puede superar * cualquier * esquema para hacer que algo sea privado. – dmckee

33

Aquí hay una manera:

int f_real_name(void) 
{ 
    ... 
} 

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

// calling f() now won't work 

otro modo, si usted puede garantizar que f()g() y son las únicas funciones en el archivo, es declarar f() como static.

EDIT: Otro truco macro para causar errores de compilación:

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

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

// f() certainly produces compiler errors here 
+1

Sin embargo, aún puede llamar a f_real_name(). –

+1

Esto es cierto, pero no es estrictamente un requisito. Juega según las reglas, no las intenciones. –

+3

Por supuesto, podemos llamar a 'f_real_name()'. También podemos llamar a 'printf()', 'malloc()' y muchas otras funciones interesantes, pero ¿qué tiene que ver con llamar a 'f()'? –

10

Usted puede hacer las funciones del módulo-privada con el static palabra clave:

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

Entonces, func() sólo puede ser llamado por otras funciones definido en el mismo archivo (técnicamente, la misma unidad de traducción : otras funciones cuyas definiciones están incluidas en una directiva #include aún pueden acceder eso). func se dice que tiene enlace interno. Se dice que todas las otras funciones (es decir, sin la palabra clave static) tienen external vinculación.

Más allá de eso, no, no hay forma de hacer que las funciones sean inaccesibles. Puede usar macros para cambiar el nombre de la función, pero otros códigos también pueden acceder a él con el nombre apropiado.

2

Solo es posible por coincidencia.

Si las funciones f() y g() están en el mismo archivo de origen y no hay otras funciones en el archivo, y si g() nunca devuelve el puntero de función a f() a cualquiera de sus llamadores , luego hacer que f() static haga el trabajo.

Si otras funciones deben aparecer en el mismo archivo fuente, colocar f() en la parte inferior del archivo como una función estática y definir g() inmediatamente después de lograr más o menos el mismo efecto, aunque si no le dijiste al compilador que generara errores en 'declaraciones faltantes', otras funciones podrían llamarlo con advertencias.

#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(); 
} 

Claramente, esta técnica no se puede ampliar de forma fiable a otro par de funciones en el mismo archivo - x() e y() - tal que x() y sólo x() puede llamar y(), mientras que g() y solo g() pueden llamar a f() al mismo tiempo.

Sin embargo, normalmente confiaría en la disciplina de los programadores y simplemente haría f() estática en el archivo fuente, junto con un comentario que solo g() podría llamarlo, y luego disciplinaría a cualquiera que modifique el código para que una función distinta de g() llama a f().

Cuestiones relacionadas