2008-11-23 4 views
17

Ich habe eine einfache Funktion, in der ein Array mit der Größe in Abhängigkeit von dem Parameter deklariert wird, der int ist.C++ Array-Größe abhängig von Funktionsparameter verursacht Kompilierungsfehler

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

    int main() { 
     return 0; 
    } 

Dieses Stück Code kompiliert auf GNU C++, in Ordnung, aber nicht auf MSVC 2005

ich folgende Kompilierungsfehler erhalten:

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

Was kann ich dies tun korrigieren?

(Ich bin daran interessiert, diese Arbeit mit MSVC zu machen, ohne dass neue Verwendung/Löschen)

Antwort

29

Was Sie es eine der Erweiterungen des GNU-Compilers für die Sprache C++ gefunden haben. In diesem Fall ist Visual C++ vollständig korrekt. Arrays in C++ müssen mit einer Größe definiert werden, bei der es sich um einen konstanten Ausdruck für die Kompilierung handelt.

Es wurde ein Feature zu C hinzugefügt, das im 1999-Update für diese Sprache namens Arrays mit variabler Länge hinzugefügt wurde, wo dies zulässig ist. Wenn Sie einen C-Compiler finden, der C99 unterstützt, ist das nicht einfach. Aber diese Funktion ist nicht Teil von C++, und wird auch nicht in der nächsten Aktualisierung des C++ - Standards hinzugefügt.

Es gibt zwei Lösungen in C++. Die erste ist ein std :: Vektor zu verwenden, der zweite nur Operator zu verwenden ist new []:

char *a = new char [n]; 

Während ich meine Antwort schrieb, ein anderer hat einen Vorschlag _alloca zu verwenden. Ich würde das dringend empfehlen. Sie würden nur eine nicht-standardmäßige, nicht-portable Methode für eine andere nur Compiler-spezifisch austauschen.

+1

Ja, aber die Zuweisung aus dem Heap, was "neu" tut, unterscheidet sich wesentlich von der Zuweisung aus dem Stack, was das OP versucht zu tun. (Es könnte Performance-sensitiven Code sein, den er zu kompilieren versucht.) –

+0

Nicht so sehr Sorgen über die Leistung für den Moment dachte ich, es war natürlich zu arbeiten ... aber wenn es nicht Teil des C++ - Standards ist, verstehe ich – xxxxxxx

+0

Re: _alloca: OP fragt nur nach äquivalenten Code, der auf MSVC funktioniert und ohne new/delete zu verwenden. –

9

Ihre Methode aus dem Stapel der Zuteilung ist eine g ++ Erweiterung. Zur Ermittlung des Äquivalents unter MSVC zu tun, müssen Sie verwenden _alloca:

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

Oh, so dass es auf Stapel zuweist! das ist wunderbar :) Danke! – xxxxxxx

+1

Beachten Sie diesen Kommentar auf der Hilfeseite alloca: BUGS Die alloca-Funktion ist Maschine und Compiler abhängig. Auf vielen Systemen ist die Implementierung fehlerhaft. Von seiner Verwendung wird abgeraten. –

+0

Ja, aber es funktioniert sicher unter MSVC, was der OP versuchte, seinen Code unter zu arbeiten. Ich benutze es seit Jahren selbst. –

2

Sie können neue verwenden/Löschen auf dem Heap reservieren/freien Speicher. Dies ist langsamer und möglicherweise fehleranfälliger als die Verwendung von char [n], aber es ist leider noch nicht Teil des C++ - Standards.

Sie können die Array-Klasse des Boost-Bereichs für eine ausnahmesichere Methode zur Verwendung von new [] verwenden. delete [] wird automatisch a aufgerufen, wenn es den Gültigkeitsbereich verlässt.

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

    /* Code here. */ 
} 

Sie können auch std :: vector und Reserve() einige Bytes verwenden:

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

    /* Code here. */ 
} 

Wenn Sie tun char [n] verwenden möchten, kompilieren als C99-Code anstelle von C++ Code.

Wenn Sie aus irgendeinem Grund unbedingt Daten auf dem Stack zuordnen müssen, verwenden Sie _alloca oder _malloca/_freea, die Erweiterungen von MSVC-Bibliotheken und dergleichen sind.

+0

Ja, aber ich verstehe nicht, warum g ++ kein Problem damit hat, während MSVC fehlschlägt – xxxxxxx

+0

Dies ist falsch, da es zuweist vom Haufen. Er möchte auf dem Stack verteilen, was die g ++ - Version tut. Der Grund, dass MSVC die ursprüngliche Version nicht kompiliert, ist, dass es eine Erweiterung von g ++ ist. –

+0

Er kann es nicht mit MSVC auf dem Stapel haben. Er kann es auf dem Heap haben, oder wenn es eine konstante Größe hat, gibt es keine Möglichkeit, ein Array variabler Größe auf dem Stack mit MSVC zu belegen. –

5

Sie verwenden etwas, das kein Standard ist. Eigentlich ist es Standard C, aber nicht C++. Wie seltsam ist das!

Erklären ein wenig mehr, Laufzeit-Größe Stack-Arrays sind nicht Teil von C++, aber sind Teil von C99, der neueste Standard für C.Deshalb werden einige Compiler es bekommen, andere nicht. Ich würde empfehlen, davon Abstand zu nehmen, um Compilerkompatibilitätsprobleme zu vermeiden.

Die alternative Implementierung der Funktionalität wäre die Verwendung von new und delete, wie von strager gepostet.

+1

Es ist überhaupt nicht "seltsam" ..! –

1

Normalerweise in C (mit Ausnahme von C99-Compilern, wie andere darauf hingewiesen haben) und C++, wenn Sie Speicher auf dem Stack zuweisen möchten, muss die Größe von dem, was Sie zuordnen möchten, zur Kompilierungszeit bekannt sein. Lokale Variablen werden auf dem Stack zugeordnet, sodass ein Array, dessen Länge zur Laufzeit von einem Funktionsparameter abhängt, diese Regel verletzt. Klein ist richtig darauf zu hinweisen, dass mit dem ‚neuen‘ Betreiber eine Möglichkeit, dieses Problem zu lösen:

 

char *a = new char [n]; 

‚a‘ eine lokale Variable ist immer noch auf dem Stapel reserviert, sondern das Seins das ganze Array (das eine variable Länge hat), es ist nur ein Zeiger auf ein Array (das immer die gleiche Größe hat und daher zur Kompilierungszeit bekannt ist). Das Array wird auf dem Heap zugewiesen, der normalerweise das Gegenstück des Stacks spielt - der Stack ist für Dinge mit einer Größe, die zur Kompilierungszeit bekannt ist, und der Heap ist für Dinge mit einer Größe, die zu einer Kompilierungszeit nicht bekannt ist.

1

Wäre es sinnvoll, einen vector<> anstelle eines Arrays zu verwenden? Oder, da Sie eine char *, eine std::string ersetzen? Diese funktionieren gut mit Laufzeitgrößen, obwohl es möglicherweise andere Gründe gibt, sie nicht zu verwenden.

2

Variable Länge Array wurde in C99 eingeführt. Es wird in gcc, aber nicht in msvc unterstützt. Laut einer Person im MSVC-Team hat Microsoft nicht vor, diese Funktion in ihrem c/C++ - Compiler zu unterstützen. Er schlug vor, in diesen Fällen std :: vector zu verwenden.

Beachten Sie, dass C99 das auf dem Stapel zugewiesene Array nicht erfordert. Der Compiler kann es auf dem Heap zuordnen. Allerdings weist gcc das Array auf dem Stapel zu.

Verwandte Themen