2017-11-12 22 views
0

ポインターの配列を指す必要がある構造体メンバーを初期化しようとしています。この考え方は、構造体の配列を静的に宣言して初期化のオーバーヘッドを避けることです。すべてのデータがコンパイル時に固定されているためです。ポインターの配列へのポインターを持つ静的構造体の初期化

残念ながら、Visual Studio 2015の下にコンパイルするコードを取得できません。次のコードは、次のエラーを生成します。C2099: initializer is not a constantlistは、文字列リテラルの固定サイズのリストでのみ初期化されるため、奇妙に見えます。

#define DATA_LIST { \ 
    L"some",  \ 
    L"example",  \ 
    L"data",  \ 
    L"in a list", \ 
    NULL   \ 
} 

#define INFO_LIST { \ 
    L"another",  \ 
    L"list",  \ 
    L"with",  \ 
    L"some",  \ 
    L"info",  \ 
    NULL   \ 
} 

typedef struct data { 
    unsigned int flag; 
    const wchar_t **list; 
} dataset, *pdataset; 

static dataset somedata[] = { 
    { .flag = 2, 
     .list = (const wchar_t *[])DATA_LIST // C2099 
    }, 
    { .flag = 4, 
     .list = (const wchar_t *[])INFO_LIST // C2099 
    } 
}; 

また、フレキシブルアレイ(const wchar_t *list[];)へのポインタを使用しようとしました。 somedataは構造体の配列として宣言することができなくなるため、理想的なソリューションではありません。その隣には、警告(C4200: nonstandard extension used: zero-sized array in struct/union)も生成されます。

typedef struct data { 
    unsigned int flag; 
    const wchar_t *list[]; // C4200 (somedata can no longer be an array of structures) 
} dataset, *pdataset; 

static dataset somedata = { 
    .flag = 2, 
    .list = DATA_LIST 
}; 

もう1つのアイデアは、ポインタの固定サイズの配列へのポインタとしてlistを定義することでした。しかし、これには、最大のリストを保持するのに十分な大きさのlistメンバでdataset構造体を定義する必要があります。また、小さなリストと1つの大きなリストがたくさんある場合は理想的ではありません。

typedef struct data { 
    unsigned int flag; 
    const wchar_t *list[sizeof (wchar_t *[])INFO_LIST/sizeof *(wchar_t *[])INFO_LIST]; 
} dataset, *pdataset; 

static dataset somedata[] = { 
    { .flag = 2, 
     .list = DATA_LIST 
    }, 
    { .flag = 4, 
     .list = INFO_LIST 
    } 
}; 

たぶん私は何かを監督していたり​​、エレガントなソリューションを提供することができる可能ないくつかの言語拡張機能はありますか?どんな提案も大歓迎です。

注:visual-c++タグが追加されていても、コードはCコードとしてコンパイルされます。


関連する可能性のある追加する別の興味深いのは、somedataが(staticキーワードなしので)非staticとして宣言されている場合、コンパイラは、いくつかの警告を生成しますが、コードをコンパイルすることが可能であるということです。 somedataを非静的として宣言することにより、コンパイル時にsomedataを初期化するために使用されるデータを強制的に強制する制約が削除されます。

コンパイルの警告に示されているように、コンパイラは、listメンバを初期化する前に、文字列リテラルのリストのアドレスを自動変数に一時的に格納しているようです。しかし、これは推測のままです。たぶん誰かが経験したことが、ここで実際に起こっていることにいくつかの光を当てることができます。

typedef struct data { 
    unsigned int flag; 
    const wchar_t **list; 
} dataset, *pdataset; 

// C4221: nonstandard extension used: 'list': cannot be initialized using 
//  address of automatic variable '$S1' 
// C4204: nonstandard extension used: non-constant aggregate initializer 
dataset somedata = { 
    .flag = 2, 
    .list = (const wchar_t *[])DATA_LIST // note: see declaration of '$S1' 
}; 

listメンバーを初期化するために、文字列リテラルのリストのアドレスで初期化された一時的な変数を使用した場合、少なくとも最後にではなく、、、コードは最終的に警告やエラーなしで罰金コンパイルします。

static const wchar_t *temp[] = DATA_LIST; 

static dataset somedata = { 
    .flag = 2, 
    .list = temp 
}; 

しかし、ポインタへのポインタとして tempを宣言し、文字列リテラルのリストを型キャストする場合、コードはもはやアクティブなエラーとしてマークされてしまう listを初期化表現としてコンパイルすることはできない。 expression must have a constant value

static const wchar_t **temp = (const wchar_t *[])DATA_LIST; 

static dataset somedata = { 
    .flag = 2, 
    .list = temp // marked as active error 
}; 

somedataを再び非静的にすると、その式はアクティブなエラーとしてマークされなくなります。しかし、コードをコンパイルしようとすると、次のエラーが再度表示されます:Visual Studio 2017は同じ方法で動作し、同様の方法でデータを整理して処理するために利用できる代替方法があるのだろうかと思います。

+0

Visual StudioのC99のサポートは事実上存在しません。これがうまくいかない原因があります。 MSVCにコードを作成させたい場合は、C90に固執してください。 – StoryTeller

+1

MSが新しい機能を実装するのに十分な時間ではありません。数年を与えてください。 –

答えて

2

MSVCはC標準に準拠していません。回避策として、あなたは代わりに複合リテラルの名前付きオブジェクトを使用することができます。

static const wchar_t *x_data_list[] = DATA_LIST; 
static const wchar_t *x_info_list[] = INFO_LIST; 

static dataset somedata[] = { 
    { .flag = 2, 
     .list = x_data_list 
    }, 
    { .flag = 4, 
     .list = x_info_list 
    } 
}; 

私はあなたが意図的にあなたのリストを非constをしたかどうかわからないんだけど、あなたは、実行時にx_data_listへの書き込みを計画していない場合それをconstにして.listメンバーにconst wchar_t * const *というメンバーを与えることができます。

+0

左に 'const'を適用すると、なぜ私はいつも' wchar_t const * const * 'に書きます。 wchar_t * const * 'strange。なぜなら、人々は' const'が右側に当てはまると考えるからです。 – Stargateur

関連する問題