2010-04-16 17 views
18

A cura di nuovo perché in origine non era chiaro che sto cercando di inizializzare le matrici in fase di compilazione, non in fase di esecuzione ...C++ inizializzazione una struttura con una serie come membro


I 've ha ottenuto la seguente TestCase ridotta:

typedef struct TestStruct 
{ 
    int length; 
    int values[]; 
}; 

TestStruct t = {3, {0, 1, 2}}; 
TestStruct t2 = {4, {0, 1, 2, 3}}; 

int main() 
{ 
    return(0); 
} 

Questo funziona con Visual C++, ma non viene compilato con g ++ sotto linux. Qualcuno può aiutarmi a rendere questo specifico tipo di inizializzatore portatile?

Ulteriori dettagli: la struttura effettiva con cui sto lavorando ha diversi altri valori int e la matrice può variare in lunghezza da una singola voce a oltre 1800 voci.

EDIT: Penso (ma non sono sicuro) che questo non sia un problema VLA. Per chiarire, sto cercando di convincere il compilatore a fare il lavoro per me in fase di compilazione. La lunghezza dell'array in fase di esecuzione è costante. Mi scuso se sbaglio; Sono principalmente un programmatore C#/Perl/Ruby che è bloccato mantenendo questa app legacy ...

Qualsiasi aiuto molto apprezzato. Grazie!

+1

Questo non è il codice legale C++. C++ non supporta matrici di lunghezza variabile o membri di array flessibili. – rlbond

+0

In realtà, funziona in gcc - hai un errore irrilevante nel tuo codice, hai dimenticato il nome della struct dopo averlo ottenuto 'typedef'ed. Però, dato che hai taggato la domanda come C++ - non vedo perché lo faresti anche tu. Le strutture typedeff sono state utilizzate per superare una limitazione di C * (rispetto a C++) *, in cui non consentiva di dichiarare una variabile struct senza la parola chiave 'struct' non necessaria. –

risposta

18

C++ non ha lo stesso membro di array flessibile dell'ultimo elemento di c99. Dovresti usare un std::vector se non sai quanti elementi o dovresti specificare quanti se lo fai.

MODIFICA: Nella modifica si è detto che la matrice è una costante di runtime, quindi specificare la dimensione e dovrebbe funzionare correttamente. g ++ non ha alcun problema con il seguente codice:

struct TestStruct { // note typedef is not needed */ 
    int length; 
    int values[3]; // specified the size 
}; 

TestStruct t = {3, {0, 1, 2}}; 

int main() { 
    // main implicitly returns 0 if none specified 
} 

EDIT: per affrontare il tuo commento, è possibile utilizzare i modelli come questo:

template <int N> 
struct TestStruct { 
    int length; 
    int values[N]; 
}; 

TestStruct<3> t3 = {3, {0, 1, 2}}; 
TestStruct<2> t2 = {2, {0, 1}}; 

int main() {} 

L'unico problema è che non v'è alcun modo semplice per inserisci t2 e t3 in un contenitore (come una lista/vettore/pila/coda/ecc perché hanno dimensioni diverse. Se vuoi, devi usare std::vector. Inoltre, se lo fai, allora non è necessario per memorizzare la dimensione (è associata al tipo), quindi puoi farlo invece:

template <int N> 
struct TestStruct { 
    static const int length = N; 
    int values[N]; 
}; 

TestStruct<3> t3 = {{0, 1, 2}}; 
TestStruct<2> t2 = {{0, 1}}; 

int main() {} 

Ma ancora una volta, non è possibile inserire t2 e t3 in una "raccolta" insieme facilmente.

EDIT: Tutto sommato, sembra che tu (a meno che non memorizzare più dati rispetto a solo alcuni numeri e le dimensioni) non hanno bisogno di una struttura a tutti, e non si può semplicemente utilizzare una pianura vecchio vettore .

Quale consentirebbe di avere sia t2 che t3 in una raccolta insieme. Sfortunatamente lo std::vector non ha (ancora) la sintassi di inizializzatore dello stile dell'array, quindi ho usato un collegamento. Ma è abbastanza semplice scrivere una funzione per popolare i vettori in un modo piacevole.

MODIFICA: OK, quindi non è necessario un insieme, ma è necessario passarlo a una funzione, è possibile utilizzare modelli per questo per preservare la sicurezza del tipo!

template <int N> 
struct TestStruct { 
    static const int length = N; 
    int values[N]; 
}; 

TestStruct<3> t3 = {{0, 1, 2}}; 
TestStruct<2> t2 = {{0, 1}}; 

template <int N> 
void func(const TestStruct<N> &ts) { /* you could make it non-const if you need it to modify the ts */ 
    for(int i = 0; i < N; ++i) { /* we could also use ts.length instead of N here */ 
     std::cout << ts.values[i] << std::endl; 
    } 
} 

// this will work too... 
template <class T> 
void func2(const T &ts) { 
    for(int i = 0; i < ts.length; ++i) { 
     std::cout << ts.values[i] << std::endl; 
    } 
} 

int main() { 
    func(t2); 
    func(t3); 
    func2(t2); 
} 
+0

È possibile specificare una dimensione di matrice in un typedef? In ogni caso, sto dichiarando diverse istanze di questa struttura, ciascuna con una diversa lunghezza. –

+0

Brillante! Grazie - questo risolve il mio problema! Grazie per l'avvertimento sui modelli non essere dello stesso tipo - non ho bisogno di un contenitore di loro, ma ho bisogno di passarli ad una funzione comune. puntatori void e typecasting dovrebbe fare il trucco c'è ... –

+0

Una nota sul perché non posso usare vettori - In realtà sto memorizzare alcune informazioni su registri della CPU che devono essere letti per diverse architetture. Oltre alla matrice di indirizzi di registro che devo leggere, ci sono circa altri 8 numeri interi a 32 bit necessari per specificare come accedere a ciascuna serie di registri. Questi altri int sono stati "ottimizzati" quando stavo creando il mio (piuttosto stupido) test case. –

1
struct TestStruct { 
    int length; 
    const int *values; 
}; 

static const uint8_t TEST_STRUCT_VAL_1[] = {0, 1, 2}; 
const TestStruct t1 = {3, TEST_STRUCT_VAL_1}; 

static const uint8_t TEST_STRUCT_VAL_2[] = {0, 1, 2, 3}; 
const TestStruct t2 = {4, TEST_STRUCT_VAL_2};` 

Nel mio caso, programmazione STM32 con gcc/g ++, l'array valore è solo memorizzazione di dati grezzi, quindi è const statico, e viene memorizzato in flash. Io uso questo modo per memorizzare i tipi di carattere per la visualizzazione dell'affissione a cristalli liquidi.

utilizzando il modello sta digitando il salvataggio, ma non il risparmio di dimensioni.

2

GCC/Clang supporta la seguente estensione

 

    typedef struct TestStruct 
    { 
     int length; 
     int* values; 
    }; 

    TestStruct t = {3, (int[]){0, 1, 2}}; 
    TestStruct t2 = {4, (int[]){0, 1, 2, 3}}; 

+0

Questo funziona solo a livello statico/globale. Se si esegue questa operazione all'interno di un metodo, il compilatore genera un array temporaneo di int, assegnarlo al struct e poi distruggere immediatamente la matrice, lasciando la struct con un cattivo puntatore; GCC avvisa se provi a farlo. – adelphus

Problemi correlati