簡體   English   中英

使用指向指針數組的指針的成員進行靜態結構初始化

[英]Static structure initialization with a pointer to array of pointers member

我正在嘗試初始化一個需要指向指針數組的結構成員。 想法是靜態聲明結構數組,以避免初始化開銷,因為所有數據都是固定的,並且在編譯時已知。

不幸的是,我無法在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
};

另一個想法是將list定義為指向固定大小的指針數組的指針。 但這需要使用list成員定義dataset結構,該list成員足夠大以容納最大列表。 當有很多小列表和一個大列表時,也不理想。

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關鍵字)時,編譯器將產生一些警告,但能夠編譯代碼。 通過聲明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非靜態,則該表達式不再標記為活動錯誤。 但是,當嘗試編譯代碼時,再次出現以下錯誤: C2099: initializer is not a constant

我想知道Visual Studio 2017行為方式是否相同,是否存在其他可用的方法來通過類似方式組織和處理數據。

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

我不確定您是否有意使列表成為非常量,但是如果您不打算在運行時寫入x_data_list ,則可以使其成為const並為.list成員指定const wchar_t * const *的類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM