2010-08-15 10 views
6

Esiste un modo per ripristinare le variabili dichiarate come statiche all'interno di una funzione? L'obiettivo è assicurarsi che la funzione non venga chiamata con valori persistenti da una chiamata non correlata. Ad esempio, ho una funzione che opera su colonne di una matrice.Come resettare le variabili statiche all'interno di una funzione

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 funzione è chiamata n volte, una volta per ogni colonna. È un modo corretto di "reimpostare" la variabile statica? Esistono altri metodi generali per reimpostare le variabili statiche? Per esempio, voglio assicurarmi che se la chiamata è fatta con una nuova matrice con dimensioni possibilmente diverse, allora il vettore v viene ridimensionato e azzerato, ecc. Sembra che il modo più semplice sia quello di chiamare la funzione con un puntatore 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

Non utilizzare variabili statiche/globali. Passa invece alla funzione un puntatore a un numero intero che il chiamante mantiene per preservare lo stato tra le chiamate. –

+0

Ho appena avuto un problema simile a quello che ho dovuto ripristinare le mie variabili statiche ma solo nel mio codice di test. Il mio hack è stato quello di impostare i puntatori di input su NULL, verificare che nel func reimpostasse la variabile in modo appropriato, usando effettivamente un valore NULL in un parametro esistente come flag. un po 'puzzolente ma funziona. – bph

+0

una classe con variabili membro statiche sarebbe la soluzione ideale forse, ma con C (no OOP) forse una struttura statica è probabilmente la soluzione elegante più vicina. – bph

risposta

0

Si consiglia di trasformarlo in una struttura e di scrivere una piccola funzione di supporto per la gestione della semantica di ciò che si sta tentando di fare. Potrebbe restituire il buffer se la richiesta è appropriata per la sua dimensione, o crearne una nuova su richiesta (e liberare quella vecchia) se necessario.

+1

Scrivi una classe wrapper? In C? – Beta

+0

Whoops, che ne dici di una funzione struct + helper? –

+0

Grazie Jesse, ho usato un ibrido degli approcci teo come indica il mio commento a Borealid. "Ripristina" è ancora gestito dalla funzione per nascondere i dettagli all'esterno. Non conosco il C++, quindi la classe wrapper è ootq. – Sue

3

Utilizzare invece una funzione di inizializzazione idempotente e variabili globali.

Ad esempio:

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

Se l'inizializzatore è davvero idempotente, si può chiamare di nuovo per ripristinare le variabili.

Se necessità questo per essere chiamato automagically, usa __attribute__((constructor)) (per GCC) in questo modo:

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

Tuttavia, si dovrebbe notare che se avete bisogno di fare questo, si dovrebbe riconsiderare utilizzando in- funzione static variabili e utilizzare invece quelli passati freschi che vengono restituiti/scritti e passati a successive chiamate correlate.

+0

Ciao, grazie per la risposta. Ho deciso di seguire il consiglio e di non usare * v come variabile statica, invece di usare solo Colonna come variabile statitc. v ora fa parte della struttura come raccomandato da Jesse sotto. passing (column = -1) ripristina la variabile statitica e reinitalizza il vettore di lavoro. Quindi viene aggiornato in modo appropriato per ogni volta (colonna! = CheColonna). Il tuo altro suggerimento sembra utile e lo apprenderò. Grazie ancora. sm – Sue

+0

hmm - questo sembra un po 'rischioso - non è sicuro che sia la soluzione più robusta con quelle variabili globali che pendono intorno allo – bph

0

Un approccio che ho visto utilizzato quando un modulo C è stato importato in C++ è stato quello di circondare l'intero modulo con un wrapper di classe e sostituire tutte le variabili statiche all'interno delle funzioni con nomi "globali" univoci al di fuori delle funzioni. Non conosco un buon modo per ottenere un effetto simile per i progetti che coinvolgono più file sorgente, anche se mi piacerebbe sapere se ne esiste uno. Ho un codice di sistema incorporato in C, che simulo aggiungendo alcuni wrapper C++ in VS2005. Ad esempio, ho i registri I/O definiti in modo che qualcosa come TX1CON = 0x5C; tradurrebbe in qualcosa come IOMAP (0x251) .P = 0x5C; IOMAP è una proprietà che invia "write 0x5C to 0x251" a un programma di simulazione hardware. Questo approccio funziona bene, ma non posso fare un reset pulito. Qualche idea?

+0

problema con questo si finisce con un sacco di altre funzioni == codice bloat. in più stai solo spingendo la responsabilità su per la scala che alla fine ti porta alla funzione anti-modello della "divinità". Non penso che ci sia una ovvia soluzione "pulita" a questo per un linguaggio non OOP – bph

+0

@Hiett: nello specifico scenario che ho descritto con i wrapper C++ in VS2005, il codice bloat si è verificato solo in un contesto di simulazione. Dal momento che il sistema reale disponeva di 128 K ROM e 4K RAM, e l'ambiente di simulazione aveva giga di RAM, e dal momento che il sistema reale probabilmente eseguiva "codice raw" meno dell'1% veloce come l'ambiente di simulazione, la mia preoccupazione era scrivere codice in tale in modo da essere efficienti sul sistema reale, senza riguardo per l'efficienza nel contesto della simulazione. Altre situazioni avrebbero altri requisiti. – supercat

0

Un approccio che può talvolta essere utile se si ha bisogno di un metodo di "reset" che può colpire un numero sconosciuto di funzioni o moduli è di avere un contatore globale per quante volte è stato chiamato quel metodo di reset, e quindi avere funzione o modulo includono codice come:

 
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 ... 
    } 
} 

In alcuni contesti multi-threading, se l'inizializzazione delle variabili statiche può dipendere alcune variabili globali, si può desiderare di sostituire il "se" con un "mentre"; in tal caso; anche in questo caso potrebbero essere necessarie barriere di memoria, anche se i requisiti esatti potrebbero variare a seconda dell'ambiente operativo.

Inoltre, un modello alternativo che può essere utile all'interno di sistemi embedded sarebbe quello di avere una variabile globale modules_initialized che viene impostato a 0 con il metodo di reset globale, e quindi avere ogni iniziale dell'unità con qualcosa di simile:

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

Ciò richiederebbe che non ci siano più di 32 ID di moduli e richiederebbe che siano allocati in modo univoco in qualche modo, ma alcuni sistemi possono gestirli in modo molto carino. Ad esempio, un linker può consentire di definire una "sezione dati" dall'indirizzo 0-31 di uno spazio indirizzo indipendente da qualsiasi altro; se ogni modulo dichiara una variabile a singolo byte all'interno di tale spazio indirizzo, il linker potrebbe generare gli indirizzi appropriati per tali variabili.

0

si potrebbe costruire la vostra funzione in modo tale che se lo si chiama con i parametri a zero, allora sarà resettare le sue variabili statiche interne

Ecco un esempio:

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 
} 

In realtà basta per chiamare la funzione per ripristinare in questo modo:

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

assicurarsi che tutti i parametri della funzione ha valori di default, se per esempio si passa un optional, ma poi ke ha sicuramente = boost :: none come valore predefinito

Problemi correlati