2010-03-26 20 views
14

Qual è il modo migliore per eseguire quanto segue in C?Inizializzazione di una struttura globale in C

#include <stdio.h> 

struct A 
{ 
    int x; 
}; 

struct A createA(int x) 
{ 
    struct A a; 
    a.x = x; 
    return a; 
} 

struct A a = createA(42); 

int main(int argc, char** argv) 
{ 
    printf("%d\n", a.x); 
    return 0; 
} 

Quando provo a compilare il codice di cui sopra, il compilatore segnala il seguente errore:

"elemento inizializzatore non è costante"

La linea cattiva è questa:

struct A a = createA(42); 

Qualcuno può spiegare cosa c'è che non va? Non ho molta esperienza in C. Grazie!

risposta

12

Perché non utilizzare l'inizializzazione statica?

struct A a = { 42 }; 
+1

Plus: non è possibile chiamare le funzioni per inizializzare staticamente i dati. Questo è ciò che il tuo errore del compilatore sta cercando di dirti. – BjoernD

+0

Va bene, ma cosa succede se ho bisogno di nidificare le inizializzazioni? Ad esempio, diciamo che una struttura B ha una A in essa. Posso inizializzare staticamente B con un A inizializzato staticamente? cioè struttura B b = createB (createA (42)) – Scott

+2

Ah, non importa. L'avevo capito. Apparentemente posso solo fare: struct B b = {{42}}; Bello! – Scott

1

Non è possibile chiamare una funzione come inizializzatore. Devi chiamarlo all'interno principale.

3

Il problema qui è che le variabili statiche globali/file in C devono avere un valore noto al momento della compilazione. Ciò significa che non è possibile utilizzare una funzione definita dall'utente per inizializzare il valore. Deve essere un'espressione costante

2

Non è possibile richiamare funzioni in fase di inizializzazione statica del genere. Nel tuo esempio, si può utilizzare semplicemente:

 
struct A a = {42}; 

Se si dispone di una configurazione più complessa, è necessario fornire una costruzione biblioteca e la funzione di distruzione di libreria che si forza gli utenti della vostra biblioteca di chiamare (supponendo che si desidera essere portabile), o dovrai usare C++ e trarre vantaggio da costruttori/distruttori, o dovrai sfruttare l'__attribute __ ((costruttore) non standard e non portatile per creare una funzione che viene eseguita all'avvio inizializzarlo.

Se si dispone di installazione più complicata, caldamente avvocato di utilizzare C++:

 
class A 
{ 
    A(){ 
     // can do initialization in the constructor 
    } 
    // ... 
}; 

A a; 

Tuttavia, se avete bisogno di attaccare con puro C, la cosa portatile da fare è usare qualcosa come:

Fondamentalmente, in quanto sopra, si inizializza la libreria con mylibrary_init e si elimina la libreria utilizzando mylibrary_destroy. Le funzioni che utilizzano la libreria richiederebbero un'istanza inizializzata di mylibrary_t, pertanto la persona che ha creato la funzione principale sarebbe stata responsabile del richiamo di mylibrary_init. È anche utile rendere la funzione di inizializzazione dipendente da un parametro "attributes" che può essere sostituito da 0 o NULL come valore predefinito. In questo modo, se estendi la tua libreria e devi accettare le opzioni di configurazione, è a tua disposizione. Questo è più un design che un approccio tecnico, però.

15
struct A a = { .x = 42 }; 

Più membri:

struct Y { 
    int r; 
    int s; 
    int t; 
}; 

struct Y y = { .r = 1, .s = 2, .t = 3 }; 

Si potrebbe anche fare

struct Y y = { 1, 2, 3 }; 

La stessa cosa funziona per i sindacati, e non è necessario includere tutti i membri o addirittura mettono loro nell'ordine corretto.

2

Per i curiosi che usano anche MSVC:

In C è possibile eseguire funzioni di inizializzazione prima principale così come è possibile in C++ (naturalmente è, come sarebbe C++ farlo se non fosse possibile in C), tuttavia potrebbe essere un po 'di confusione se non hai letto come funziona la tua libreria runtime.

Per farla breve:

#pragma section(".CRT$XIU",long,read) 

int 
init_func() 
{ 
// initialization 

return 0; // return 0 is mandatory 
} 

__declspec(allocate(".CRT$XIU")) 
int (*global_initializer)() = init_func; 

quindi non è come testo di partenza compatta come in C++, ma si può fare. Inoltre, prima di utilizzare consiglio di comprendere prima il formato PE, quindi leggere crt \ src \ crt0.c e crt \ src \ crt0dat.c (cercare _cinit in entrambi i file) nella directory di installazione MSVC in modo da sapere cosa sta succedendo.

+0

Esiste un equivalente gcc? – rkellerm

+0

@rkellerm risposta facile: non la penso così. risposta difficile: ci sono più di un libcs ​​per gcc. Penso che il modo più semplice per scoprirlo sia cercare "_start" nel repository del codice sorgente della tua libc. Questa è la prima funzione chiamata nell'elfo. Di solito il file che contiene questo simbolo si chiama crt0something.c. newlib per esempio non ha tale inizializzazione, imposta argc, argv e va per main. Ma non sarebbe difficile aggiungere del codice per farlo. La compilazione di libc è di solito abbastanza mal di testa. – Pyjong

+0

@rkellerm ok bud. Oggi avevo davvero bisogno di questa funzionalità, quindi ho annusato in glibc 2.4. Risulta che è ancora più facile che con il compilatore MS. Nel caso in cui tu voglia ancora saperlo - dichiara semplicemente la tua funzione come __attribute __ ((costruttore)) initializer_fn() e c'è il tuo costruttore prematrimoniale C;) – Pyjong

Problemi correlati