2010-08-15 33 views
6

¿Hay alguna manera de restablecer las variables declaradas como estáticas dentro de una función? El objetivo es asegurarse de que la función no se llame con los valores persistentes de una llamada no relacionada. Por ejemplo, tengo una función operando en columnas de una matriz.Cómo restablecer variables estáticas dentro de una función

int foo(matrix *A, int colnum, int rownum){ 
static int whichColumn; 
static int *v; //vector of length A->nrows 
    if (column != whichColumn){ 
    memset(v,0,size); 
    whichColumn = which; 
    } 
    //do other things 
} 

La función se llama n veces, una para cada columna. ¿Es esta una forma adecuada de "restablecer" la variable estática? ¿Hay otras formas generales a prueba de tontos para restablecer las variables estáticas? Por ejemplo, quiero asegurarme de que si la llamada se realiza con una nueva matriz con dimensiones posiblemente diferentes, entonces el vector v se redimensiona y se pone a cero, etc. Parece que la manera más fácil es llamar a la función con un puntero NULL:

int foo(matrix *A, int colnum, int rownum){ 
static int whichColumn; 
static int *v; //vector of length A->nrows 
    if (A == NULL){ 
    FREE(v); 
    whichColumn = 0; 
    } 
    //do other things 
} 
+2

No utilice variables estáticas/globales. En su lugar, pase la función un puntero a un número entero que la persona que llama mantiene para preservar el estado de las llamadas. –

+0

Acabo de tener un problema similar cuando tuve que restablecer mis variables estáticas pero solo en mi código de prueba. Mi truco fue establecer punteros de entrada en NULL, verificar eso en el func y luego reiniciar la variable según sea apropiado, efectivamente usando un valor NULL en un parámetro existente como indicador. un poco apestoso pero funciona. – bph

+0

una clase con variables miembro estáticas sería su solución ideal quizás, pero con C (sin OOP) quizás una estructura estática sea probablemente la solución elegante más cercana. – bph

Respuesta

0

Recomiendo convertirlo en una estructura y escribir una pequeña función de ayuda para gestionar la semántica de lo que estás tratando de hacer. Podría devolver el búfer si la solicitud es apropiada para su tamaño, o crear uno nuevo a pedido (y liberar el anterior) si es necesario.

+1

¿Escribir una clase contenedora? ¿Cª? – Beta

+0

Vaya, ¿qué tal una función struct + helper? –

+0

Gracias Jesse, utilicé un híbrido de los enfoques teo como indica mi comentario a Borealid. "Restablecer" todavía está administrado por la función para ocultar detalles en el exterior. No sé C++, entonces la clase contenedora es ootq. – Sue

3

Utilice en su lugar una función de inicializador idempotente y variables globales.

Por ejemplo:

int foo; 
int *m = NULL; 

static void InitVars() { 
    foo = 0; 
    if (m != NULL) { 
     free(m); 
    } 
    m = malloc(sizeof(int)*5); 
    memset(m, 0, sizeof(int)*5); 
} 

Si su inicializador es realmente idempotente, se le puede llamar de nuevo para restablecer las variables.

Si necesidad que esto se llama automágicamente, utiliza __attribute__((constructor)) (GCC), así:

static void InitVars __attribute__((constructor))(); 

Sin embargo, debe tener en cuenta que si usted tiene que hacer esto, usted debe reconsiderar el uso de in- Funciona con las variables static y, en su lugar, utiliza las nuevas que se han enviado, que se devuelven/escriben y se pasan a las llamadas relacionadas posteriores.

+0

Hola, gracias por la respuesta. Decidí seguir el consejo y no usar * v como una variable estática, sino simplemente usar whichColumn como una variable statitc. v ahora es parte de la estructura recomendada por Jesse a continuación. passing (columna = -1) restablece la variable statítica y revitaliza el vector de trabajo. Luego se actualiza apropiadamente para cada momento (column! = WhichColumn). Tu otra sugerencia parece útil y la aprenderé. Gracias de nuevo. sm – Sue

+0

hmm - esto parece un poco arriesgado - no estoy seguro de que sea la solución más robusta con esas variables globales alrededor de – bph

0

Un enfoque que he visto utilizar cuando se importó un módulo C a C++ fue rodear todo el módulo con un contenedor de clase, y reemplazar todas las variables estáticas dentro de funciones con varaibles "globales" con nombres únicos fuera de las funciones. No conozco ninguna buena manera de lograr un efecto similar para los proyectos que involucran varios archivos fuente, aunque me gustaría saber si existe alguno. Tengo un código de sistema integrado en C, que simulo agregando algunos wrappers de C++ en VS2005. Por ejemplo, tengo registros de E/S definidos para que algo como TX1CON = 0x5C; se traduciría en algo como IOMAP (0x251) .P = 0x5C; IOMAP es una propiedad que enviaría "write 0x5C to address 0x251" a un programa de simulación de hardware. Este enfoque funciona bien, pero no puedo hacer un reinicio limpio. ¿Algunas ideas?

+0

problema con esto es que terminas con un montón más funciones == código de hinchazón. Además, usted está empujando la responsabilidad hacia arriba en la escalera que finalmente lo llevará a la función anti dios 'patrón'. No creo que exista una solución "limpia" obvia para esto para un lenguaje no OOP – bph

+0

@Hiett: en el escenario particular que describí con los contenedores de C++ en VS2005, la inflamación del código solo se produjo en un contexto de simulación. Como el sistema real tenía 128K ROM y 4K RAM, y el entorno de simulación tenía gigas de RAM, y dado que el sistema real probablemente ejecutaba "código sin formato" menos del 1% tan rápido como el entorno de simulación, mi preocupación era escribir código en tal manera de ser eficiente en el sistema real, sin tener en cuenta si la eficiencia en el contexto de la simulación. Otras situaciones tendrían otros requisitos. – supercat

0

Un enfoque que a veces puede ser útil si se necesita un método de "reinicio" que puede alcanzar un número desconocido de funciones o módulos es tener un contador global de cuántas veces se ha llamado ese método de restauración, y luego tener cada función o módulo incluyen un código como:

 
extern unsigned long global_reset_count; 

void do_something(int whatever) 
{ 
    static ... this, that, the other, etc. ...; 
    static unsigned long my_reset_count; 

    if (my_reset_count != global_reset_count) 
    { 
    my_reset_count = global_reset_count; 
    ... initialize this, that, the other, etc ... 
    } 
} 

En algunos contextos multi-threading, si la inicialización de las variables estáticas puede depender de algunas variables globales, uno puede desear reemplazar el "si" con un "tiempo"; En ese caso; las barreras de memoria también pueden ser necesarias en tal caso, aunque los requisitos exactos variarían dependiendo del entorno operativo.

Además, un patrón alternativo que puede ser útil en sistemas embebidos sería tener una variable global modules_initialized que obtiene el valor 0 por el método de restablecimiento global, y luego tener cada inicio de módulo con algo como:

 
    if (!atomic_bit_test_and_set32(&modules_initialized, FOOBOZZ_MODULE_ID)) 
    { 
    ... Initialize module FOOBOZZ ... 
    } 

Esto requeriría que no hubiera más de 32 ID de módulo, y requeriría que se asignaran de forma única de alguna manera, pero algunos sistemas pueden manejarlo bastante bien. Por ejemplo, un enlazador puede permitir definir una "sección de datos" desde la dirección 0-31 de un espacio de direcciones independiente de cualquier otro; si cada módulo declara una variable de un solo byte dentro de ese espacio de direcciones, el enlazador podría generar las direcciones apropiadas para esas variables.

0

se podría construir su función de tal manera que si usted llama con parámetros de cero, entonces se restablecerá sus variables estáticas internas

aquí es un ejemplo:

int foo(matrix *A = NULL, int colnum = 0, int rownum = 0) 
{ 
    static int whichColumn; 
    static int *v; //vector of length A->nrows 

    if (A == NULL){ 
    FREE(v); 
    whichColumn = 0; 
    } 
    //do other things 
} 

En realidad sólo hay para llamar a la función para restablecer la siguiente manera:

foo(); // internal values would then be reset 

Asegúrese de que todos los parámetros a la función tiene valores por defecto, si por ejemplo se pasa un opcional, a continuación, ma Asegúrese de que tiene = boost :: none como valor predeterminado

Cuestiones relacionadas