2017-11-12 18 views
0

포인터 배열을 가리켜 야하는 구조체 멤버를 초기화하려고합니다. 아이디어는 모든 데이터가 고정되어 컴파일 시간에 알려지기 때문에 초기화 오버 헤드를 피하기 위해 구조체의 배열을 정적으로 선언하는 것입니다.포인터 배열에 대한 포인터를 사용하여 정적 구조 초기화

불행히도 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 구성원으로 정의되어야합니다. 또한 작은 목록이 많고 하나의 큰 목록이있을 때 이상적이지 않습니다.

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이 같은 방식으로 작동하는지, 유사한 방법으로 데이터를 구성하고 처리 할 수있는 대체 방법이 있는지 궁금합니다.

+0

Visual Studio에서 C99을 지원하는 것은 사실상 존재하지 않습니다. 이 기능을 작동시키지 않으면 실패 할 수 있습니다. MSVC에서 코드를 작성하려면 C90에 고정하십시오. – StoryTeller

+1

16 년은 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 *'에 쓰는지,'const wchar_t * const *'이상한 사람들은'const'가 오른쪽에 적용된다고 생각하기 때문에. – Stargateur