2008-11-23 9 views
17

Ho una semplice funzione in cui una matrice viene dichiarata con la dimensione a seconda del parametro che è int.La dimensione dell'array C++ dipende dal parametro funzione causa errori di compilazione

void f(int n){ 
     char a[n]; 
    }; 

    int main() { 
     return 0; 
    } 

Questo pezzo di codice viene compilato bene su GNU C++, ma non su MSVC 2005.

Ottengo i seguenti errori di compilazione:

.\main.cpp(4) : error C2057: expected constant expression 
    .\main.cpp(4) : error C2466: cannot allocate an array of constant size 0 
    .\main.cpp(4) : error C2133: 'a' : unknown size 

Cosa posso fare per correggere questo?

(io sono interessato a fare questo lavoro con MSVC, senza l'utilizzo di new/delete)

risposta

29

Che cosa avete trovato una delle estensioni del compilatore Gnu per il linguaggio C++. In questo caso, Visual C++ è completamente corretto. Le matrici in C++ devono essere definite con una dimensione che è un'espressione costante in fase di compilazione.

C'era una funzionalità aggiunta a C nell'aggiornamento del 1999 a quel linguaggio chiamato array di lunghezza variabile, dove questo è legale. Se riesci a trovare un compilatore C che supporti C99, non è facile. Ma questa caratteristica non fa parte del C++ standard, non sarà aggiunta nel prossimo aggiornamento allo standard C++.

Esistono due soluzioni in C++. Il primo è quello di utilizzare uno std :: vector, il secondo è solo per utilizzare operatore new []:

char *a = new char [n]; 

Mentre scrivevo la mia risposta, un altro inviato un suggerimento di utilizzare _alloca. Consiglio vivamente contro questo. Dovresti semplicemente scambiare un metodo non standard e non portatile con un altro solo come compilatore specifico.

+1

Sì, ma l'allocazione dall'heap, che fa "new", è molto diversa dall'allocazione dallo stack che è ciò che l'OP sta tentando di fare. (Potrebbe essere un codice sensibile alle prestazioni che sta cercando di compilare.) –

+0

Non mi preoccupo molto delle prestazioni per il momento, ho pensato che fosse naturale lavorare ... ma se non fa parte dello standard C++ capisco – xxxxxxx

+0

Re: _alloca: OP chiedeva solo di ottenere codice equivalente funzionante su MSVC e senza usare new/delete. –

9

tuo metodo di ripartizione dalla pila è un'estensione g ++. Per fare l'equivalente sotto MSVC, è necessario utilizzare _alloca:

char *a = (char *)_alloca(n); 
+0

Oh, quindi si assegna in pila! è meraviglioso :) Grazie! – xxxxxxx

+1

Nota questo commento dalla pagina di manuale alloca: BUGS La funzione alloca è macchina e compilatore dipendente. Su molti sistemi la sua implementazione è bacata. Il suo uso è scoraggiato. –

+0

Sì, ma funziona sicuramente con MSVC, che è ciò che l'OP stava cercando di far funzionare sotto il suo codice. L'ho usato da anni. –

2

Puoi usare new/delete per allocare/memoria libera sul mucchio. Questo è più lento e probabilmente più incline all'errore rispetto all'utilizzo di char [n], ma non è ancora parte dello standard C++, purtroppo.

È possibile utilizzare la classe dell'array con scope di boost per un metodo eccezionalmente sicuro per l'utilizzo di new []. delete [] viene automaticamente chiamato a quando esce dallo scope.

void f(int n) { 
    boost::scoped_array<char> a(new char[n]); 

    /* Code here. */ 
} 

È anche possibile utilizzare std :: vector, e riserva() alcuni byte:

void f(int n) { 
    std::vector<char> a; 
    a.resize(n); 

    /* Code here. */ 
} 

Se fai voler utilizzare char [n], compilare il codice C99 invece di C++ codice.

Se è assolutamente necessario allocare i dati nello stack per qualche motivo, utilizzare _alloca o _malloca/_freea, che sono le estensioni fornite dalle librerie MSVC e così via.

+0

sì, ma non capisco il motivo per cui g ++ non ha alcun problema con questo, mentre non riesce MSVC – xxxxxxx

+0

Questo è sbagliato perché assegna dal mucchio. Vuole allocare nello stack che è ciò che fa la versione g ++. Il motivo per cui MSVC non compila la versione originale è che si tratta di un'estensione g ++. –

+0

Non può averlo in pila con MSVC. Può averlo sull'heap o avere dimensioni costanti, non c'è modo di allocare una matrice di dimensioni variabili nello stack con MSVC. –

5

Si sta utilizzando qualcosa che non è uno standard. In realtà è standard C ma non C++. Com'è strano!

Spiegando un po 'di più, eseguire array di stack di dimensioni temporali non fanno parte di C++, ma fanno parte di C99, l'ultimo standard per C.Ecco perché alcuni compilatori lo otterranno, mentre altri no. Raccomanderei di astenersi dall'utilizzarlo, per evitare problemi di compatibilità del compilatore.

La alternativo implementazione della funzionalità sarebbe utilizzando new e delete, come pubblicato da Strager.

+1

Non è affatto "strano"! –

1

genere in C (eccetto compilatori C99 come altri hanno fatto notare) e C++, se si vuole allocare memoria sullo stack, la dimensione di ciò che si vuole allocare deve essere conosciuta al momento della compilazione. Le variabili locali sono allocate nello stack, quindi una matrice la cui lunghezza dipende da un parametro di funzione in fase di esecuzione viola questa regola. Klein è corretto sottolineare che utilizzando l'operatore 'nuovo' è un modo per risolvere questo problema:

 

char *a = new char [n]; 

'a' è ancora una variabile locale allocato sullo stack, ma invece di essere l'intero array (che ha lunghezza variabile), è solo un puntatore a un array (che è sempre della stessa dimensione, e quindi noto al momento della compilazione). L'array è allocato sull'heap, che in genere riproduce la controparte dello stack: lo stack è per oggetti con una dimensione nota in fase di compilazione e l'heap è per oggetti con una dimensione non nota in fase di compilazione.

1

sarebbe ragionevole usare un vector<> piuttosto che un array? Oppure, dal momento che stai sostituendo uno char *, uno std::string? Questi funzionano bene con il dimensionamento del runtime, anche se potrebbero esserci altri motivi per non utilizzarli.

2

matrice di lunghezza variabile è stata introdotta in C99. È supportato in gcc ma non in msvc. Secondo una persona del team MSVC, Microsoft non ha in programma di supportare questa funzionalità nel proprio compilatore c/C++. Ha suggerito di usare std :: vector in questi casi.

noti che C99 non richiede che l'array allocato sullo stack. Il compilatore può allocarlo sull'heap. Tuttavia, gcc alloca l'array nello stack.