2013-08-11 5 views
2

C 구조의 가변 길이 배열에 대한 질문이 있습니다 (http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html).공용 구조체 유형 및 가변 배열 구성원

typedef struct { 
    size_t N; 
    int elems[]; 
} A_t; 

이제 일반적인 접근 방식은

A_t * a = malloc(sizeof(A_t) + sizeof(int) * N) 
a->N = N; 
.... 

지금이 다른 구조체에 물건을 통합 또는 스택 기반 할당을 할 때 어색한 것 같다, 아주 분명하다. 그래서 다음 snipet 같은 일이 N!=0

struct { 
    A_t a; 
    A_t b; /// !!!!! 
    double c; /// !!!!! 
}; 

가 지금은 또 다른 유형을 정의하여 다음

typedef struct { 
    size_t N; 
    int elems[5]; 
} A_5_t; 

struct { 
    A_5_t a; 
    A_5_t b; 
    double c; // should work here now. 
} mystruct; 

하고있는 것처럼 사용과 같은 용도로 허용 할 수 있어야한다고 생각 실패 할 수밖에 없다 그것을 A_t 구조입니다. 함수 void foo(A_t * arg1);을 호출 할 때는 foo((A_t*) (&mystruct.b))과 같은 것을 사용해야합니다. 어느 것이 - 나에게 - 조금 서투른 것처럼 보인다. 그러므로 나는 이것을 할 수있는 더 좋은 방법이 있는지 궁금해합니다. 어떻게 든이 유니온 타입을 사용할 수 있을지 궁금합니다.

가변 길이 배열을 사용하면 구조에서 데이터를 한 조각으로 가질 수 있기 때문에 깊고 얕은 복사본이 걱정되는 대신 단일 명령으로 구조체를 복사 할 수 있으므로,

+0

귀하의 링크 http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html은 C90에 대한 GCC 확장입니다. 귀하의 예제 인'int elems [];'는 "flexible array member"라는 C99 (및 C11) 기능을 사용합니다. '[0]'과'[] '의 차이점을 보았습니까? 'elems'는'int elems [];에서 길이가 0 인 배열이 아닌 ** **입니다. 길이가 0 인 배열은 모든 C 표준에 의해 금지됩니다 (확장을위한 좋은 장소가되지만 불완전한 배열이되지는 않습니다). –

+0

제로 길이와 플렉시벨 길이 어레이의 차이점을 확인합니다. 링크 된 GNU 페이지가 실제로 문서화됩니다. 내 질문은 struct 및 flexibel 배열 길이를 효과적으로 할당하는 패턴을 사용하는 방법에 관한 것이 었습니다. – wirrbel

답변

0

지금 알아 냈습니다. (솔루션은 위에 제공된대로 gnu 문서에서 실제로 설명되었습니다.) 구조체 선언 다음에 배열 선언을 추가하면 "빈"유연 배열에 직접 인접한 연속 메모리 범위가 생성됩니다. 따라서 b.A.elems[i]b.elems_[i]과 동일한 데이터를 참조합니다.

이 배열의 메모리가 실제로 구조에 속한다는 것을 나타내는 식별자를 선택하는 것이 좋습니다. 적어도 내가 어떻게 사용하는지.

typedef struct { 
    size_t N; 
    double elems[]; 
} A_t; 
typedef struct { 
    A_t a; 
    double elems_[4]; 
} B_t; 
void foo(A_t * arg1) { 
    for (size_t i=0; i < arg1->N; ++i) { 
     printf("%f\n", arg1->elems[i]); 
    } 
} 
int main(int argc, char *argv[]) { 
    B_t b; 
    b.a.N = 4; 
    for (int i=0; i < 4; ++i) { 
     b.elems_[i] = 12.4; 
    } 
    foo(&b.a); 
} 
1

다층 질문이 있습니다. 이 하나의 예에서

:

struct { 
    A_t b; 
    double c; /// fails 
}; 

나는 시도 할 것이다 :

struct { 
    double c; 
    A_t b; 
}; 

항상 마지막에 구조체의 변수 부분을 놓습니다. 참고, 나는 GCC를 사용하지 않으므로 이것을 시도해 보라. 아마 작동 할 수도있다.

@wirrbel에서 제공하는 요구 사항을 추적하려면 다음 구조체는 NOT 가변 길이이지만 가변 길이의 정수 배열을 정의하고 액세스 할 수 있습니다.

typedef struct { 
    size_t N; 
    int *(elems[]); // parens to ensure a pointer to an array 
} A_t; 

A_t *a = malloc //etc. 

a->elems = malloc(sizeof(int) * N); 

이러한 방식으로, 다수의 구조가보다 일반적인 구조에 포함될 수있다.

+0

안녕하세요, 이것은 좋은 접근 방법 일 수 있지만 A_t 유형의 두 멤버와 함께 실패합니다. 나는 아마 그 점에서 나의 예제 코드를 단순화 시켰을 것이다. – wirrbel

+0

@wirrbel, 귀하의 의견에 대한 답변을 확대했습니다. 재검토를하고 필요한 경우 더 자세한 정보를 제공하면 답변 해 드리겠습니다. – JackCColeman

1

아니, 당신이 struct, A_tA_5_t 일반적으로 서로 호환되지 않습니다.그 이유는 가변 배열을 가진 버전이 필드 길이가 고정 된 버전보다 elems 필드 앞에 다른 패딩을 가질 수 있기 때문입니다.

컴파일러가 다른 패딩을 구현하는지 여부에 관계없이 offsetof 매크로를 사용하여 테스트 할 수 있습니다. 그러나 오프셋이 특정 컴파일러와 플랫폼에서 동일하더라도, 이식 가능한 코드를 원한다면 의존하지 않는 것이 좋습니다.