In C99 können Sie ein flexibles Array-Mitglied einer Struktur als solches deklarieren:
struct blah
{
int foo[];
};
Als jedoch jemand hier bei der Arbeit versuchte, Code mit clang in C++ zu kompilieren, funktionierte diese Syntax nicht. (Es hat mit MSVC funktioniert.) Wir mussten es konvertieren in:
struct blah
{
int foo[0];
};
Beim Durchsehen des C++-Standards fand ich überhaupt keinen Hinweis auf flexible Member-Arrays; Ich dachte immer [0]
war eine ungültige Deklaration, aber anscheinend ist sie für ein flexibles Member-Array gültig. Sind flexible Member-Arrays in C++ tatsächlich gültig? Wenn ja, ist die richtige Erklärung []
oder [0]
?

Martin v. Löwen
C++ wurde erstmals 1998 standardisiert, also vor der Hinzufügung flexibler Array-Mitglieder zu C (was neu in C99 war). 2003 gab es eine Berichtigung zu C++, die jedoch keine relevanten neuen Funktionen hinzufügte. Die nächste Revision von C++ (C++2b) befindet sich noch in der Entwicklung, und es scheint, dass ihr noch keine flexiblen Array-Mitglieder hinzugefügt werden.

Michael Burr
C++ unterstützt keine flexiblen C99-Array-Member am Ende von Strukturen, entweder mit einer leeren Indexnotation oder a 0
Indexnotation (ausgenommen herstellerspezifische Erweiterungen):
struct blah
{
int count;
int foo[]; // not valid C++
};
struct blah
{
int count;
int foo[0]; // also not valid C++
};
Soweit ich weiß, wird C++0x dies auch nicht hinzufügen.
Wenn Sie das Array jedoch auf 1 Element skalieren:
struct blah
{
int count;
int foo[1];
};
Der Code wird kompiliert und funktioniert recht gut, aber es ist ein technisch undefiniertes Verhalten. Sie können den entsprechenden Speicher mit einem Ausdruck zuweisen, der wahrscheinlich keine Off-by-One-Fehler enthält:
struct blah* p = (struct blah*) malloc( offsetof(struct blah, foo[desired_number_of_elements]);
if (p) {
p->count = desired_number_of_elements;
// initialize your p->foo[] array however appropriate - it has `count`
// elements (indexable from 0 to count-1)
}
Es ist also zwischen C90, C99 und C++ portierbar und funktioniert genauso gut wie die flexiblen Array-Mitglieder von C99.
Raymond Chen hat dazu einen netten Bericht geschrieben: Warum enden manche Strukturen mit einem Array der Größe 1?
Hinweis: In Raymond Chens Artikel gibt es einen Tippfehler/Fehler in einem Beispiel, das das „flexible“ Array initialisiert. Es sollte lauten:
for (DWORD Index = 0; Index < NumberOfGroups; Index++) { // note: used '<' , not '='
TokenGroups->Groups[Index] = ...;
}
Der zweite enthält keine Elemente, sondern zeigt direkt danach blah
. Wenn Sie also eine Struktur wie diese haben:
struct something
{
int a, b;
int c[0];
};
Sie können Dinge wie folgt tun:
struct something *val = (struct something *)malloc(sizeof(struct something) + 5 * sizeof(int));
val->a = 1;
val->b = 2;
val->c[0] = 3;
In diesem Fall c
verhält sich wie ein Array mit 5 int
s, aber die Daten im Array werden nach dem sein something
Struktur.
Das Produkt, an dem ich arbeite, verwendet dies als Zeichenfolge mit der Größe:
struct String
{
unsigned int allocated;
unsigned int size;
char data[0];
};
Aufgrund der unterstützten Architekturen verbraucht dies mehr als 8 Bytes allocated
.
Natürlich ist das alles C, aber g++ zum Beispiel akzeptiert es ohne Probleme.
Wenn Sie Ihre Anwendung darauf beschränken können, nur wenige bekannte Größen zu benötigen, können Sie mit einer Vorlage effektiv ein flexibles Array erreichen.
template <typename BASE, typename T, unsigned SZ>
struct Flex : public BASE {
T flex_[SZ];
};
Wenn Sie nur wollen
struct blah { int foo[]; };
dann brauchen Sie die Struktur überhaupt nicht und können sich einfach mit einem malloc’ed/new’ed int-Array befassen.
Wenn Sie am Anfang einige Mitglieder haben:
struct blah { char a,b; /*int foo[]; //not valid in C++*/ };
dann in C++, ich nehme an, Sie könnten ersetzen foo
mit einer foo
Mitgliedsfunktion:
struct blah { alignas(int) char a,b;
int *foo(void) { return reinterpret_cast<int*>(&this[1]); } };
Beispielanwendung:
#include <stdlib.h>
struct blah {
alignas(int) char a,b;
int *foo(void) { return reinterpret_cast<int*>(&this[1]); }
};
int main()
{
blah *b = (blah*)malloc(sizeof(blah)+10*sizeof(int));
if(!b) return 1;
b->foo()[1]=1;
}
Ein Vorschlag ist in Arbeit und könnte zu einer zukünftigen C++-Version führen. Sehen http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1039r0.html für Details (der Vorschlag ist ziemlich neu, daher sind Änderungen vorbehalten)

St. Antario
Ich hatte das gleiche Problem, um ein flexibles Array-Member zu deklarieren, das aus C++-Code verwendet werden kann. Indem man durchschaut glibc
Header Ich habe festgestellt, dass es einige Verwendungen von flexiblen Array-Mitgliedern gibt, z. B. in struct inotify
die wie folgt deklariert ist (Kommentare und einige nicht verwandte Mitglieder weggelassen):
struct inotify_event
{
//Some members
char name __flexarr;
};
Die __flexarr
Makro wiederum ist definiert als
/* Support for flexible arrays.
Headers that should use flexible arrays only if they're "real"
(e.g. only if they won't affect sizeof()) should test
#if __glibc_c99_flexarr_available. */
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
# define __flexarr []
# define __glibc_c99_flexarr_available 1
#elif __GNUC_PREREQ (2,97)
/* GCC 2.97 supports C99 flexible array members as an extension,
even when in C89 mode or compiling C++ (any version). */
# define __flexarr []
# define __glibc_c99_flexarr_available 1
#elif defined __GNUC__
/* Pre-2.97 GCC did not support C99 flexible arrays but did have
an equivalent extension with slightly different notation. */
# define __flexarr [0]
# define __glibc_c99_flexarr_available 1
#else
/* Some other non-C99 compiler. Approximate with [1]. */
# define __flexarr [1]
# define __glibc_c99_flexarr_available 0
#endif
Ich kenne mich nicht aus MSVC
Compiler, aber wahrscheinlich müssten Sie je nach ein weiteres bedingtes Makro hinzufügen MSVC
Ausführung.
9640600cookie-checkSind flexible Array-Member in C++ gültig?yes
Kannst du nicht einfach a verwenden
std::vector<int>
Mitglied und kümmern Sie sich um interessantere Sachen? Oder ist das ein Layoutproblem?– fredoverflow
10. Dezember 2010 um 19:59 Uhr
Dieses flexible-Array-Member-Tag scheint ein bisschen … einsam zu sein. Aber vielleicht liegt es nur an mir.
– Markus Borkenhagen
10. Dezember 2010 um 20:09 Uhr
@FredOverflow: Manchmal müssen Strukturen vorhanden sein, die sowohl in C als auch in C++ verwendet werden können (System-APIs sind ein sehr häufiges Beispiel).
– Michael Burr
10. Dezember 2010 um 20:45 Uhr
@FredOverflow, normalerweise würde ich das tun, aber in diesem Fall ist eine zusammenhängende Zuweisung für erforderlich
blah
mit variabler Größefoo
. Es ist sicherlich eine gute Designfrage, warum wir es überhaupt brauchen, auf die ich hier nicht eingehen kann.– MSN
10. Dezember 2010 um 21:11 Uhr
Eigentlich ist diese spezifische Konstruktion gemäß der illegal C99-Standardwie es heißt: “als Sonderfall das letzte Element einer Struktur mit mehr als eine Named Member kann einen unvollständigen Array-Typ haben; das nennt man a flexibles Array-Mitglied.” Damit
blah
braucht ein zusätzliches Mitglied, eins davorfoo
um in C99 gültig zu sein.– Hallo Auf Wiedersehen
18. Oktober 2020 um 20:24 Uhr