ポインターの配列を指す必要がある構造体メンバーを初期化しようとしています。この考え方は、構造体の配列を静的に宣言して初期化のオーバーヘッドを避けることです。すべてのデータがコンパイル時に固定されているためです。ポインターの配列へのポインターを持つ静的構造体の初期化
残念ながら、Visual Studio 2015
の下にコンパイルするコードを取得できません。次のコードは、次のエラーを生成します。C2099: initializer is not a constant
。 list
は、文字列リテラルの固定サイズのリストでのみ初期化されるため、奇妙に見えます。
#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
は同じ方法で動作し、同様の方法でデータを整理して処理するために利用できる代替方法があるのだろうかと思います。
Visual StudioのC99のサポートは事実上存在しません。これがうまくいかない原因があります。 MSVCにコードを作成させたい場合は、C90に固執してください。 – StoryTeller
MSが新しい機能を実装するのに十分な時間ではありません。数年を与えてください。 –