2011-12-31 2 views
16

I가 내가 인스턴스를 생성하고 유연한 배열 구성원과 구조를 초기화하는 방법에 대한 몇 가지 기본적인 인터넷 검색을 수행 (그러나 실패) 한어떻게 유연한 배열 구성원과 구조를 초기화

typedef struct _person { 
    int age; 
    char sex; 
    char name[]; 
}person; 

다음과 같은 구조 malloc()을 사용하지 않습니다.

: 우리 struct a의 인스턴스를 생성하고, 상술 한 바와 같이

struct a p1 = {10, 'm'}; 

같은하지만 유연한 배열 구조 (같은 _person위한 초기화 수

struct a { 
    int age; 
    int sex; 
}; 

같은 통상 구조물) 인스턴스를 만들고 초기화하는 방법은 보통 structures에 대해 어떻게 할 수 있습니까?

심지어 가능합니까? 그렇다면 초기화하는 동안 배열 크기를 전달하고 초기화 할 실제 값은 어떻게 전달합니까?

(또는)

인가 그것을 참 C99 명세서에서 언급 malloc() 사용하는 유일한 방법은가요 배열 구성을 만드는 것을 - 6.7.2.1 Structure and union specifiers - point #17을?!

+1

구조체는 컴파일 시간 크기를 가질 수 없습니다. – Anycorn

+6

@Anycorn : 가변 배열 멤버가있는 구조체는 컴파일 시간 크기를가집니다. –

+3

GCC는 당신이'struct {size_t len; int data []; } x = {4, {1, 2, 3, 4}}; 그러면 작동하지만 휴대용이 아닙니다. 여러분의 플랫폼의 버전 인'alloca'를 항상 더 포팅 가능한 솔루션으로 들여다 볼 수는 있지만, 모두 똑같은 방식으로 동작하고 동일한 구현 방식을 유지해야합니다. –

답변

8

아니요. 유연한 배열은 항상 수동으로 할당해야합니다. 그러나 calloc을 사용하여 고정 파트를 초기화하고 가변 리터럴을 초기화하여 고정 파트를 초기화 할 수 있습니다. 이 같은 할당 inline 기능에 그 포장 것 :

typedef struct person { 
    unsigned age; 
    char sex; 
    size_t size; 
    char name[]; 
} person; 

inline 
person* alloc_person(int a, char s, size_t n) { 
    person * ret = calloc(sizeof(person) + n, 1); 
    if (ret) memcpy(ret, 
        &(person const){ .age = a, .sex = s, .size = n}, 
        sizeof(person)); 
    return ret; 
} 

는 할당이 호출에 성공했을 경우이 검사를 떠난다 관찰합니다.

여기에 포함 된대로 size 필드가 필요하지 않으면 매크로로도 충분합니다. memcpy하기 전에 calloc의 반품을 확인하는 것이 불가능할뿐입니다. 지금까지 프로그래밍 한 모든 시스템에서 이것은 비교적 잘 중단됩니다. 일반적으로 나는 return of malloc is of minor importance이라고 생각하지만 의견은 주제에 따라 크게 다릅니다.

이것은 아마도 (특별한 경우) 주변의 코드를 통합하는 최적화에 더 많은 기회를 줄 수 :

#define ALLOC_PERSON(A, S, N)         \ 
((person*)memcpy(calloc(sizeof(person) + (N), 1),    \ 
       &(person const){ .age = (A), .sex = (S) },  \ 
       sizeof(person))) 

편집 :이 더 잘 될 수 있다고 케이스는 기능을 할 때보다 AS은 컴파일시 상수입니다.이 경우 const 수식이므로 복합 리터럴을 정적으로 할당 할 수 있으며 컴파일 타임에 초기화 할 수 있습니다. 또한 동일한 값을 가진 여러 할당이 코드에 나타나면 컴파일러는 해당 복합 리터럴의 단 하나의 복사본 만 구현할 수 있습니다.

+1

'calloc()'의 결과를 체크하지 않은 상태로 복사하는 것은 위험합니다; 할당이 실패하면 코어 덤프 (또는 당신이 원했을 가능성이 낮은 다른 정의되지 않은 동작)가 발생합니다. –

+0

@JonathanLeffler, 수정됩니다. 나는 그것을 함수에 통합 할 것이다. marcro에 대해서는 malloc의 반환을 확인하는 것에 대한 일반적인 호언 장담을 참조 할 것입니다. –

+0

인라인 함수 솔루션이 좋습니다. 매크로는 IMHO보다 이점이 없습니다. 그것은 읽을 수없고, calloc 반환 값을 체크하지 않으며, 더 잘 수행되지 않을 것입니다. 일반적으로 매크로는 인라인 함수보다 성능이 좋지 않습니다 (때로는 악화됩니다 - 매크로를 두 번 평가하는 strlen()을 전달하는 것을 고려하십시오). – ugoren

2

유연한 배열 멤버가있는 구조 유형은 유연한 배열 멤버가 생략 된 것처럼 처리 될 수 있으므로 이와 같이 구조를 초기화 할 수 있습니다.

person p = { 10, 'x' }; 

그러나 할당가요 어레이 및 그 단부가 유효하지 않은 하나 이상의 포인터를 플렉시블 어레이의 멤버를 액세스하거나 형성하려는 시도의 어떠한 부재가 없다. 실제로이 배열에 요소가있는 유연한 배열 멤버를 사용하여 구조의 인스턴스를 만드는 유일한 방법은 동적으로 메모리를 할당하는 것입니다 (예 : malloc).

+2

동일한 구문을 사용하는 유연한 배열 멤버를 지정할 수있는 GCC 확장이 있습니다 (해당되는 경우). –

4

사용할 수있는 몇 가지 트릭이 있습니다. 그것은 귀하의 특정 응용 프로그램에 따라 다릅니다.

단일 변수를 초기화 할 경우 올바른 크기의 구조를 정의 할 수 있습니다 :

struct { 
     int age; 
     char sex; 
     char name[sizeof("THE_NAME")]; 
    } your_variable = { 55, 'M', "THE_NAME" }; 

문제는 당신이 "사람"과 같은 변수를 해석하는 포인터 캐스팅을 사용해야한다는 것입니다 (예 : ..

union { 
struct { ..., char name[sizeof("THE_NAME")]; } x; 
person p; 
} your_var = { 55, 'M', "THE_NAME" }; 

때문에, your_var.p 유형 "사람" 이다 또한 매크로를 사용할 수 있습니다 : "* (사람 *) (& your_variable)은"그러나이 피하기 위해 포함 된 조합을 사용할 수 있습니다 이니셜 라이저를 정의하면 문자열 o를 쓸 수 있습니다. 한 번만 :

#define INIVAR(x_, age_, sex_ ,s_) \ 
    union {\ 
    struct { ..., char name[sizeof(s_)]; } x;\ 
    person p;\ 
    } x_ = { (age_), (sex_), (s_) } 

INIVAR(your_var, 55, 'M', "THE NAME"); 

또 다른 문제는이 트릭이 "사람"의 배열을 만드는 데 적합하지 않다는 것입니다. 배열의 문제는 모든 요소가 동일한 크기를 가져야한다는 것입니다. 이 경우 char[] 대신 const char *을 사용하는 것이 더 안전합니다. 또는 동적 할당을 사용하십시오.)