web-dev-qa-db-ja.com

柔軟な配列メンバーはC ++で有効ですか?

C99では、構造体の柔軟な配列メンバーを次のように宣言できます。

struct blah
{
    int foo[];
};

しかし、ここにいる誰かがC++でclangを使用してコードをコンパイルしようとしたとき、その構文は機能しませんでした。 (これはMSVCで動作していました。)変換する必要がありました。

struct blah
{
    int foo[0];
};

C++標準を調べたところ、柔軟なメンバー配列への参照はまったく見つかりませんでした。いつも思っていた[0]は無効な宣言でしたが、明らかにフレキシブルメンバー配列の場合は有効です。柔軟なメンバー配列は実際にC++で有効ですか?もしそうなら、正しい宣言です[]または[0]

39
MSN

C++は1998年に最初に標準化されたため、C(C99の新機能)への柔軟な配列メンバーの追加に先んじています。 2003年にC++の修正がありましたが、関連する新機能は追加されませんでした。 C++の次のリビジョン(C++ 0x)はまだ開発中であり、柔軟な配列メンバーが追加されていないようです。

26

C++は、空のインデックス表記または0インデックス表記(ベンダー固有の拡張を除く)を使用して、構造の最後にあるC99フレキシブル配列メンバーをサポートしていません。

struct blah
{
    int count;
    int foo[];  // not valid C++
};

struct blah
{
    int count;
    int foo[0]; // also not valid C++
};

私の知る限り、C++ 0xもこれを追加しません。

ただし、配列のサイズを1要素にすると、次のようになります。

struct blah
{
    int count;
    int foo[1];
};

物事は有効であり、非常にうまく機能します。 1つずれるエラーが発生する可能性が低い式を使用して、適切なメモリを割り当てることができます。

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

したがって、C90、C99、C++間で移植可能であり、C99の柔軟な配列メンバーと同様に機能します。

Raymond Chenはこれについて素晴らしい記事を書いています: なぜいくつかの構造がサイズ1の配列で終わるのですか?

注:Raymond Chenの記事では、「柔軟な」配列を初期化する例にタイプミス/バグがあります。それは読むべきです:

for (DWORD Index = 0; Index < NumberOfGroups; Index++) { // note: used '<' , not '='
  TokenGroups->Groups[Index] = ...;
}
20
Michael Burr

2つ目は要素を含まず、blahの直後を指します。したがって、次のような構造がある場合:

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

あなたはこのようなことをすることができます:

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

この場合、cは5つのintsの配列として動作しますが、配列内のデータはsomething構造の後になります。

私が取り組んでいる製品は、これをサイズの文字列として使用します。

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

サポートされているアーキテクチャのため、これは8バイトとallocatedを消費します。

もちろん、これはすべてCですが、たとえばg ++は問題なくそれを受け入れます。

3
terminus

いくつかの既知のサイズのみを必要とするようにアプリケーションを制限できる場合は、テンプレートを使用して柔軟な配列を効果的に実現できます。

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

提案が進行中であり、将来のC++バージョンになる可能性があります。詳細は https://thephd.github.io/vendor/future_cxx/papers/d1039.html を参照してください(この提案はかなり新しいため、変更される可能性があります)

1
pqnet

あなただけが欲しいなら

struct blah { int foo[]; };

その後、構造体はまったく必要ありません。malloc'ed/ new'ed int arrayを処理するだけで済みます。

最初にメンバーがいる場合:

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

次に、C++では、foofooメンバー関数に置き換えることができると思います。

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

使用例:

#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

C++コードから使用できる柔軟な配列メンバーを宣言するために同じ問題に直面しました。 glibcヘッダーを調べたところ、柔軟な配列メンバーの使用方法がいくつかあることがわかりました。 struct inotifyは次のように宣言されています(コメントと無関係なメンバーは省略されています):

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

__flexarrマクロは次のように定義されます

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

私はMSVCコンパイラに慣れていませんが、MSVCバージョンに応じて、条件付きマクロをもう1つ追加する必要があります。

0
St.Antario