web-dev-qa-db-fra.com

Les éléments de tableau flexibles sont-ils valides en C ++?

En C99, vous pouvez déclarer un membre de la matrice flexible d'une structure en tant que telle:

struct blah
{
    int foo[];
};

Cependant, lorsque quelqu'un au travail a essayé de compiler du code à l'aide de Clang en C++, cette syntaxe n'a pas fonctionné. (Il travaillait avec MSVC.) Nous avons dû la convertir en:

struct blah
{
    int foo[0];
};

En regardant à travers la norme C++, je n'ai trouvé aucune référence aux tableaux de membre flexibles du tout; J'ai toujours pensé [0] a été une déclaration invalide, mais apparemment pour un tableau de membre flexible, il est valide. Les matrices de membres flexibles sont-elles réellement valables en C++? Si c'est le cas, est la déclaration correcte [] ou [0]?

39
MSN

C++ a été standardisé pour la première fois en 1998. Il prédit donc l'ajout d'éléments de réseau flexibles à C (qui était nouveau en C99). Il y avait un corrigendum à C++ en 2003, mais cela n'a ajouté aucune nouvelle fonctionnalité pertinente. La prochaine révision de C++ (C++ 0x) est toujours en cours de développement et semble que les membres de la matrice flexibles ne soient pas ajoutés.

26
Martin v. Löwis

La seconde ne contiendra pas d'éléments mais aura plutôt pointer juste après blah. Donc, si vous avez une structure comme celle-ci:

struct something
{
  int a, b;
  int c[0];
};

vous pouvez faire des choses comme ceci:

struct something *val = (struct something *)malloc(sizeof(struct something) + 5 * sizeof(int));
val->a = 1;
val->b = 2;
val->c[0] = 3;

Dans ce cas c _ va se comporter comme une matrice avec 5 ints, mais les données de la matrice seront après la structure something.

Le produit sur lequel je travaille est utilisé comme une chaîne de taille:

struct String
{
  unsigned int allocated;
  unsigned int size;
  char data[0];
};

En raison des architectures prises en charge, cela consomme 8 octets plus allocated.

Bien sûr, tout cela est c mais g ++, par exemple l'accepte sans attelage.

3
terminus

Si vous pouvez limiter votre application pour ne nécessiter que quelques tailles connues, vous pouvez alors obtenir efficacement une matrice flexible avec un modèle.

template <typename BASE, typename T, unsigned SZ>
struct Flex : public BASE {
    T flex_[SZ];
};
2
jxh

Une proposition est en cours et peut apporter une version future C++. Voir https://thephd.github.io/vendor/future_cxx/papers/d1039.html Pour plus de détails (la proposition est assez nouvelle, elle est donc soumise à des modifications)

1
pqnet

Si vous voulez seulement

struct blah { int foo[]; };

ensuite, vous n'avez pas besoin de la structure du tout et vous pouvez simplement traiter avec un tableau Malloc'ed/New'ed int.

Si vous avez des membres au début:

struct blah { char a,b; /*int foo[]; //not valid in C++*/ };

ensuite, en C++, je suppose que vous pourriez remplacer foo avec une fonction de membre foo:

struct blah { alignas(int) char a,b; 
    int *foo(void) { return reinterpret_cast<int*>(&this[1]); } };

Exemple d'utilisation:

#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;
}
1
PSkocik

J'ai confronté le même problème à déclarer un élément de tableau flexible qui peut être utilisé à partir du code C++. En regardant à travers glibc-en-têtes, j'ai constaté qu'il y avait quelques utilisateurs de membres de la matrice flexibles, par ex. dans struct inotify qui est déclaré comme suit (commentaires et certains membres non liés omis):

struct inotify_event
{
  //Some members
  char name __flexarr;
};

Les __flexarr macro, à son tour est définie comme

/* 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

Je ne suis pas familier avec MSVC compilateur, mais vous devrez probablement ajouter une macro plus conditionnelle en fonction de la version MSVC.

0
St.Antario