2010-04-16 7 views
18

Edited wieder, weil es ursprünglich war nicht klar, dass ich versuche, die Arrays bei der Kompilierung zu initialisieren, nicht zur Laufzeit ...C++ Initialisieren eine Struktur mit einem Array als Mitglied


I habe folgenden reduzierten Testfall bekommt:

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

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

int main() 
{ 
    return(0); 
} 

Dies funktioniert mit Visual C++, aber nicht kompiliert mit g ++ unter linux. Kann jemand mir helfen, diese bestimmte Art des Initialisierers tragbar zu machen?

Weitere Details: die tatsächliche Struktur, mit der ich arbeite, hat mehrere andere int-Werte, und das Array kann in der Länge von einem einzelnen Eintrag bis zu 1800 Einträge reichen.

EDIT: Ich denke (aber bin mir nicht sicher), dass dies kein VLA Problem ist. Um zu verdeutlichen, versuche ich den Compiler dazu zu bringen, die Arbeit für mich zur Kompilierzeit zu erledigen. Die Länge des Arrays zur Laufzeit ist konstant. Entschuldigung, wenn ich falsch liege; Ich bin in erster Linie ein C#/Perl/Ruby-Programmierer, der fest ist, diese Legacy-App zu pflegen ...

Jede Hilfe sehr geschätzt. Vielen Dank!

+1

Dies ist nicht legal C++ Code. C++ unterstützt Arrays variabler Länge oder flexible Array-Member nicht. – rlbond

+0

Eigentlich funktioniert es in gcc - Sie haben einen irrelevanten Fehler in Ihrem Code, Sie haben den Namen der Struktur vergessen, nachdem Sie es 'typedef'ed bekommen haben. Obwohl Sie die Frage als C++ getaggt haben - ich verstehe nicht, warum Sie das überhaupt tun würden. Typedeffing-Strukturen wurde verwendet, um eine Einschränkung von C * (im Gegensatz zu C++) * zu umgehen, wo Sie keine Strukturvariable ohne das unnötige 'struct'-Schlüsselwort deklarieren konnten. –

Antwort

18

C++ hat nicht dasselbe flexible Array-Element wie das letzte Element wie c99. Sie sollten eine std::vector verwenden, wenn Sie nicht wissen, wie viele Elemente Sie angeben sollen oder wie viele Sie angeben sollen.

EDIT: Sie haben in Ihrem Edit gesagt, dass das Array eine Laufzeitkonstante ist, also geben Sie die Größe an und es sollte gut funktionieren. g ++ hat kein Problem mit dem folgenden Code:

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: Ihren Kommentar zu adressieren, können Sie Vorlagen wie folgt verwenden:

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() {} 

Das einzige Problem ist, dass es keine einfache Möglichkeit, zu lege t2 und t3 in einen container (wie eine liste/vector/stack/queue/etc, weil sie unterschiedliche größen haben. Wenn du das willst, solltest du std::vector verwenden. Wenn du das tust, dann ist es auch nicht notwendig Speichern Sie die Größe (es ist mit dem Typ verbunden). So können Sie stattdessen dies tun:

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() {} 

Aber noch einmal, Sie können nicht einfach t2 und t3 in einer "Sammlung" zusammen setzen.

EDIT: Alles in allem, es klingt wie Sie (es sei denn, Sie mehr Daten speichern als nur ein paar Zahlen und die Größe) braucht nicht eine Struktur überhaupt, und nicht nur ein einfaches altes Vektor verwenden .

typedef std::vector<int> TestStruct; 


int t2_init[] = { 0, 1, 2 }; 
TestStruct t3(t3_init, t3_init + 3); 

int t2_init[] = { 0, 1 }; 
TestStruct t2(t2_init, t2_init + 2); 

int main() {} 

Welche würden Sie beide t2 und t3 in einer Sammlung zusammen haben. Leider hat std::vector (noch) keine Initialisierungssyntax im Array-Stil, also habe ich eine Verknüpfung verwendet. Aber es ist einfach genug, um eine Funktion zu schreiben, um die Vektoren auf eine schöne Art zu bevölkern.

EDIT: OK, Sie brauchen also keine Sammlung, aber Sie müssen es an eine Funktion übergeben, können Sie Vorlagen für die Typsicherheit verwenden!

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

Können Sie eine Array-Größe in einem Typedef angeben? In jedem Fall deklariere ich mehrere Instanzen dieser Struktur mit jeweils unterschiedlich langen Arrays. –

+0

Brilliant! Danke - das löst mein Problem! Danke für die Warnung über Vorlagen nicht den gleichen Typ - ich brauche keinen Container von ihnen, aber ich muss sie an eine gemeinsame Funktion übergeben. Void Pointer und Typecasting sollten dort die Lösung sein ... –

+0

Ein Hinweis darüber, warum ich nicht einfach Vektoren verwenden kann - ich speichere tatsächlich einige Informationen über CPU-Register, die für verschiedene Architekturen gelesen werden müssen. Zusätzlich zu dem Array von Registeradressen, die ich lesen muss, sind ungefähr 8 andere 32-Bit-Ganzzahlen erforderlich, um anzugeben, wie auf jede Reihe von Registern zugegriffen wird. Diese anderen Ints wurden "optimiert", als ich meinen (ziemlich dummen) Testfall erstellte. –

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

In meinem Fall STM32-Programmierung mit gcc/g ++ ist der Wert Array nur Rohdatenspeicherung, so dass es static const ist, und würde im Flash gespeichert werden. Ich benutze diese Art, um Schriftartmuster für LCD-Anzeige zu speichern.

Verwenden der Vorlage wird gespeichert, aber nicht speichern.

2

GCC/Clang unterstützen die folgende Erweiterung

 

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

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

+0

Dies funktioniert nur auf der statischen/globalen Ebene. Wenn Sie dies innerhalb einer Methode tun, generiert der Compiler ein temporäres Array von Ints, weist es der Struktur zu und zerstört dann sofort das Array, wobei die Struktur mit einem schlechten Zeiger zurückbleibt. GCC warnt, wenn Sie dies versuchen. – adelphus