C 프로그래밍 언어 표준에 따라 구조체를 초기화하는 방법


465

struct 요소를 초기화하고 선언과 초기화로 나누고 싶습니다. 이것이 내가 가진 것입니다 :

typedef struct MY_TYPE {
  bool flag;
  short int value;
  double stuff;
} MY_TYPE;

void function(void) {
  MY_TYPE a;
  ...
  a = { true, 15, 0.123 }
}

이것이 로컬 변수를 선언하고 초기화하는 방법입니까? MY_TYPE C 프로그래밍 언어 표준 (C89, C90, C99, C11 등)에 따라 입니까? 아니면 더 좋거나 최소한 작동하는 것이 있습니까?

업데이트 필자는 필요에 따라 모든 하위 요소를 설정하는 정적 초기화 요소를 갖게되었습니다.


3
더 나은 대답을 받아 들여야합니다. 나쁜 코딩 가이드를 사용해야한다는 것을 알지만 여전히 올바른 방법이라고 다른 사람들에게 제안해서는 안됩니다.
Karoly Horvath

@KarolyHorvath 글쎄, 대부분의 좋은 답변은 C99에만 해당됩니다. 어쩌면 내 질문은 stackoverflow.com/questions/6624975/… 의 사본입니다 .
cringe

그것이 원래 의도라면, 아마도 그렇습니다. 그러나 1) 투표는 매우 오도 될 것입니다. 2) 상단 검색 조회수에서 이것은 C99 방법을 보여주는 유일한 방법입니다 ..... C99 데모를 위해이 페이지를 다시 사용하는 것이 좋습니다 ... (분명히 사람들은이 페이지를 링크하여 방법을 보여주기 시작했습니다. ) 그것을 할
카 롤리 호 바스에게

10
수락 된 (그리고 많이 찬성 된) 답변이 원래 게시 된 것처럼 실제로 질문에 답변하지 않는다는 점에 흥미가 있습니다. 지정된 이니셜 라이저는 선언을 초기화에서 분리 하는 OP의 문제를 해결하지 못합니다 . 1999 년 이전 C의 경우 유일한 해결책은 각 구성원에게 할당하는 것입니다. C99 이상의 경우 CesarB의 답변에서와 같이 복합 리터럴이 솔루션입니다. (물론 지정자 유무에 관계없이 실제 이니셜 라이저가 더 나을 것이지만, OP는 정말 나쁜 코딩 표준으로 안장을 apparent 것 같습니다.)
Keith Thompson

31
엄밀히 말하면, "ANSI C"라는 용어는 이제 ANSI가 채택한 2011 ISO 표준을 나타냅니다. 그러나 실제로 "ANSI C"라는 용어는 일반적으로 (공식적으로 사용되지 않는) 1989 표준을 나타냅니다. 예를 들어 "gcc -ansi"는 여전히 1989 표준을 시행합니다. 1990 년, 1999 년 및 2011 년 표준을 게시 한 ISO이므로 "ANSI C"라는 용어를 사용하지 말고 혼동 가능성이있는 경우 표준 날짜를 참조하는 것이 가장 좋습니다.
Keith Thompson

답변:


728

(ANSI) C99에서는 지정된 이니셜 라이저를 사용할 수 있습니다 를 하여 구조를 초기화 .

MY_TYPE a = { .flag = true, .value = 123, .stuff = 0.456 };

편집 : 다른 멤버는 0으로 초기화됩니다. "생략 된 필드 멤버는 정적 저장 기간을 갖는 오브젝트와 동일하게 내재적으로 초기화됩니다." ( https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html )


87
감사합니다 정적 oxeRay2f ray = {.unitDir = {.x = 1.0f, .y = 0.0f}};
오리온 엘렌 질

4
이것은 전혀 질문에 대답하지 않습니다. OP는 초기화와 선언을 분리하려고합니다.
osvein

3
C99! = ANSI C-C89 또는 C90에서는 작동하지 않습니다.
Tim Wißmann

3
C99 ANSI C입니다. 이것을
Cutberto Ocampo

3
@CutbertoOcampo 나는 지금 무슨 일이 있었는지 이해합니다. 원래 질문은 ANSI C의 솔루션을 요구하는 것이 었으며, 분명히 그는 C89에 대해서만 답변을 원했습니다. 2016 년에 질문이 편집되고 "ANSI C"가 제거되었으므로이 답변과 설명에 "(ANSI) C99"가 언급 된 이유를 이해하기 어렵습니다.
Étienne

198

복합 리터럴로 할 수 있습니다 . 이 페이지에 따르면 C99에서 작동합니다 ( ANSI C 로 계산 ).

MY_TYPE a;

a = (MY_TYPE) { .flag = true, .value = 123, .stuff = 0.456 };
...
a = (MY_TYPE) { .value = 234, .stuff = 1.234, .flag = false };

이니셜 라이저의 지정은 선택 사항입니다. 당신은 또한 쓸 수 있습니다 :

a = (MY_TYPE) { true,  123, 0.456 };
...
a = (MY_TYPE) { false, 234, 1.234 };

따라서 지정된 이니셜 라이저는 동시에 선언하고 정의 할 때 사용되지만 복합 리터럴은 이미 선언 된 변수를 정의 할 때 사용합니까?
Geremia

@ Geremia 먼저 두 경우 모두 구조체를 정의해야하지만 지정된 이니셜 라이저를 사용하면 구조체가 변경되는 경우 코드를 더 읽기 쉽고 오류에 더 탄력적으로 만듭니다.
hoijui

2
조금 까다 롭습니다. 여러 번 (일부 성공) 지정된 초기화 프로그램을 사용하려고했습니다. 그러나 객체 생성시 이니셜 라이저를 사용하지 않으면 캐스트가 있어야한다는 것이 분명해졌습니다 (귀하의 @philant의 예 덕분입니다). 그러나 이제는 초기화 프로그램이 객체 생성 이외의 시간에 사용되는 경우 (예 :와 같이) 엄격하게 지정된 초기화 프로그램이 아닌 복합 리터럴 이라고합니다 . ideone.com/Ze3rnZ
sherrellbc

93

ANSI C 99에 대한 답변을 이미 받았으므로 ANSI C 89에 대한 뼈를 던질 것입니다. ANSI C 89를 사용하면 다음과 같이 구조체를 초기화 할 수 있습니다.

typedef struct Item {
    int a;
    float b;
    char* name;
} Item;

int main(void) {
    Item item = { 5, 2.2, "George" };
    return 0;
}

구조체에서 하나의 객체 / 변수를 초기화하는 순간 다른 모든 변수가 기본값으로 초기화됩니다.

구조체의 값을 초기화하지 않으면 모든 변수에 "쓰레기 값"이 포함됩니다.

행운을 빕니다!


3
초기화에 변수를 사용할 수 있습니까?
Cyan

2
@Cyan 자동 저장 시간이있는 개체를위한 것입니다. 에서 6.7.9 13)를 참조하십시오 open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf을 . 전역 객체의 경우 리터럴로 거의 제한됩니다. const가더라도 다른 전역 객체는 사용할 수 없습니다.
PSkocik

C 99와의 유일한 차이점은 지정을 지정할 수 없다는 것입니다.
Akaisteph7

42

a = (MYTYPE){ true, 15, 0.123 };

C99에서 잘 될 것입니다.


1
솔직히 대답이 가장 유용한 것이라고 생각합니다.
user12211554

22

당신은 거의 그것을 가지고 ...

MY_TYPE a = { true,15,0.123 };

'struct initialize c'에 대한 빠른 검색 은 이것을 보여줍니다.


1
표준 C에서는 이것이 사실이지만 ANSI C (99?)에서는 그렇지 않다고 생각합니다. 또한 선언 및 초기화를 한 번에 수행 할 수없는 코딩 규칙에 묶여 있으므로 분할하고 모든 하위 요소를 초기화해야합니다.
싫증이 나다

8
초기화는 선언 시점에서만 가능합니다. 그것이 '초기화'라는 의미입니다. 그렇지 않으면 정의되지 않은 값을 변수 / 구조체의 초기 값으로 허용 한 다음 나중에 값을 할당합니다.
Kieveli

8
음 ... 의도적으로 나쁜 코딩 규칙이 있습니까? 아마도 당신은 "Resource Acquisition Is Initialization"( en.wikipedia.org/wiki/RAII )에 글을 쓴 사람을 소개해야합니다
James Curran

이 시점에서이 규칙을 약간 변경할 수는 없습니다. 그것을 코딩하는 것은 끔찍한 느낌입니다. 그리고 개정 번호와 같은 관리 정보를 가진 정적 코드 헤더와 같이 70 년대 중 많은 다른 규칙이 있습니다. 소스가 변경되지 않은 경우에도 모든 릴리스에 대한 변경 사항 ...
싫증이 나다

19

C 프로그래밍 언어 표준 ISO / IEC 9899 : 1999 (일반적으로 C99)는 다음과 같이 지정된 이니셜 라이저 를 사용 하여 구조 또는 공용체 멤버를 초기화 할 수 있습니다.

MY_TYPE a = { .stuff = 0.456, .flag = true, .value = 123 };

ISO / IEC 9899 : 1999 표준의 paragraph 7섹션 6.7.8 Initialization에 다음과 같이 정의되어 있습니다.

지정자가 형식을 갖는 경우
. 식별자
는 현재 객체 (아래에 정의 됨)에 구조 또는 공용체 유형을 가져야하며 식별자는 해당 유형의 멤버 이름이어야합니다.

참고 paragraph 9동일한 섹션의 그 상태 :

명시 적으로 다르게 언급 된 경우를 제외하고,이 하위 절의 목적 상 구조 및 공용체 유형의 명명되지 않은 객체 멤버는 초기화에 참여하지 않습니다. 구조 객체의 이름이없는 멤버는 초기화 후에도 불확실한 값을 갖습니다.

그러나 GNU GCC 구현에서 생략 된 멤버는 0 또는 0과 유사한 유형에 적합한 값으로 초기화됩니다. 6.27 GNU GCC 문서의 지정된 이니셜 라이저 에 명시된대로 :

생략 된 필드 멤버는 정적 저장 기간이있는 오브젝트와 동일하게 내재적으로 초기화됩니다.

공식 블로그 게시물 C ++ Conformance Roadmap 에 따르면 Microsoft Visual C ++ 컴파일러는 버전 2013 이후 지정된 초기화 프로그램을 지원해야합니다 . 단락 Initializing unions and structs 이니셜 라이저의 MSDN의 Visual Studio 문서에서 기사는 익명의 회원들이 GNU GCC 유사 제로와 같은 적절한 값으로 초기화 제안합니다.

ISO / IEC 9899 : 1999를 대체 한 ISO / IEC 9899 : 2011 표준 (일반적으로 C11)은 섹션 아래에 지정된 이니셜 라이저를 유지합니다6.7.9 Initialization . 또한 paragraph 9변경되지 않은 상태로 유지됩니다.

ISO / IEC 9899 : 2011을 대체 한 새로운 ISO / IEC 9899 : 2018 표준 (일반적으로 C18)은 섹션 아래에 지정된 이니셜 라이저를 유지합니다 6.7.9 Initialization. 또한 paragraph 9변경되지 않은 상태로 유지됩니다.


2
처음에는 이것을 수락 된 답변의 편집으로 제안했지만 거부되었습니다. 따라서 나는 그것을 답변으로 게시합니다.
PF4Public

"명명되지 않은 회원"은 "생략 된 필드"를 의미하는 것이 아니라에있는 노조와 같은 "익명 회원"을 의미한다고 생각 struct thing { union { char ch; int i; }; };합니다. 나중에 표준은 다음과 같이 말합니다. "괄호로 묶은 목록에 집계의 요소 나 멤버보다 이니셜 라이저가 적거나 배열의 요소보다 알려진 크기의 배열을 초기화하는 데 사용되는 문자열 리터럴의 문자가 더 적다면, 나머지 집계는 정적 저장 시간을 갖는 객체와 동일하게 암시 적으로 초기화됩니다. "
emersion

14

Ron Nuni가 말한 것처럼 :

typedef struct Item {
    int a;
    float b;
    char* name;
} Item;

int main(void) {
    Item item = {5, 2.2, "George"};
    return 0;
}

기억해야 할 중요한 것은 구조체에서 하나의 객체 / 변수조차 초기화 할 때 다른 모든 변수는 기본값으로 초기화됩니다.

구조체에서 값을 초기화하지 않으면 (즉, 변수를 선언 한 경우) 모두 variable.members"쓰레기 값"을 포함합니다. 선언이 로컬 인 경우에만 !

선언이 전역 또는 정적 인 경우 (이 경우와 같이) 초기화되지 않은 모든 항목은 다음과 같이 variable.members자동으로 초기화됩니다.

  • 0 정수 및 부동 소수점
  • '\0'에 대한 char물론 이것은 단지와 동일한의 ( 0char 정수 타입)
  • NULL 포인터.

로컬 / 글로벌에 관심이있는 것은 struct tm 시간 값에도 적용됩니다. 나는 로컬 하나를 가지고 있었고 어떤 경우에는 DST가 켜져 있었고 다른 경우에는 내가 한 일이 아니기 때문에 그렇지 않았습니다. 나는 DST (tm_isdst 필드)를 사용하지 않았으며, 이것은 strptime에서 왔지만 time_t로 변환 할 때 일부 시간이 지났습니다.
Alan Corey

3
void function(void) {
  MY_TYPE a;
  a.flag = true;
  a.value = 15;
  a.stuff = 0.123;
}

23
일단 '초기화가 할당과 다릅니다'라고 들었습니다. 초기화가 아닌 할당이 아닌가?
Hayri Uğur Koltuk

2

MS가 C99로 업데이트되지 않은 경우 MY_TYPE a = {true, 15,0.123};



2

나는이 답변들 중 어느 것도 마음에 들지 않아서 나 자신을 만들었다. 이것이 ANSI C인지 아닌지 모르겠습니다. 기본 모드에서는 GCC 4.2.1입니다. 나는 브라케팅을 기억할 수 없으므로 데이터의 하위 세트로 시작하고 종료 될 때까지 컴파일러 오류 메시지와 싸우십시오. 가독성은 나의 최우선 과제입니다.

    // in a header:
    typedef unsigned char uchar;

    struct fields {
      uchar num;
      uchar lbl[35];
    };

    // in an actual c file (I have 2 in this case)
    struct fields labels[] = {
      {0,"Package"},
      {1,"Version"},
      {2,"Apport"},
      {3,"Architecture"},
      {4,"Bugs"},
      {5,"Description-md5"},
      {6,"Essential"},
      {7,"Filename"},
      {8,"Ghc-Package"},
      {9,"Gstreamer-Version"},
      {10,"Homepage"},
      {11,"Installed-Size"},
      {12,"MD5sum"},
      {13,"Maintainer"},
      {14,"Modaliases"},
      {15,"Multi-Arch"},
      {16,"Npp-Description"},
      {17,"Npp-File"},
      {18,"Npp-Name"},
      {19,"Origin"}
    };

데이터가 탭으로 구분 된 파일로 시작되어 다른 것으로 마사지하기 위해 검색을 대체 할 수 있습니다. 네, 데비안입니다. 따라서 {}의 외부 쌍 (배열을 나타냄)과 내부의 각 구조체에 대한 다른 쌍입니다. 사이에 쉼표가 있습니다. 헤더에 물건을 넣는 것이 꼭 필요한 것은 아니지만 내 구조체에 약 50 개의 항목이 있으므로 별도의 파일에 저장하여 코드에서 혼란을 피하고 교체하기가 더 쉽습니다.


3
구조체 배열의 초기화에 대해서는 의문의 여지가 없었습니다! 당신의 대답에는 오버 헤드가 있습니다.
Victor Signaevskyi

내 요점은 이미 각 값을 설정하기 위해 =를 사용하여 vs.
Alan Corey

이 원칙은 그것이 하나의 구조체이든 또는 그 배열이든 적용됩니다. =를 사용하면 실제로 초기화되지는 않습니다.
Alan Corey

0

C의 구조는 다음과 같이 선언하고 초기화 할 수 있습니다.

typedef struct book
{
    char title[10];
    char author[10];
    float price;
} book;

int main() {
    book b1={"DS", "Ajay", 250.0};

    printf("%s \t %s \t %f", b1.title, b1.author, b1.price);

    return 0;
}

0

집계 유형 초기화에 대한 Microsoft Visual Studio 2015 설명서를 읽었 지만 아직 모든 형식의 초기화{...} 지만 여기에서 대해 설명하지만``designator ''라는 도트로 초기화하는 것은 언급되지 않았습니다. 또한 작동하지 않습니다.

C99 표준 장 6.7.8 초기화는 지정자의 가능성을 설명하지만, 복잡한 구조에 대해서는 분명하지 않습니다. PDF로 C99 표준 .

내 마음에, 그것은 더 나을 수 있습니다

  1. = {0};모든 정적 데이터에 -initialization을 사용하십시오 . 기계 코드에 대한 노력이 적습니다.
  2. 예를 들어 매크로를 사용하여 초기화

    typedef MyStruct_t{ int x, int a, int b; } MyStruct; define INIT_MyStruct(A,B) { 0, A, B}

매크로는 조정될 수 있으며, 인수 목록은 변경된 구조체 내용과 독립적 일 수 있습니다. 적은 수의 요소를 초기화해야하는 경우에 적합합니다. 중첩 된 구조체에도 적합합니다. 3. 간단한 형태는 다음과 같습니다. 서브 루틴에서 초기화합니다.

void init_MyStruct(MyStruct* thiz, int a, int b) {
  thiz->a = a; thiz->b = b; }

이 루틴은 C에서 ObjectOriented처럼 보입니다. C ++로 컴파일 thiz하지 말고 사용하십시오 this!

MyStruct data = {0}; //all is zero!
init_MyStruct(&data, 3, 456);

0

구조체를 초기화하는 좋은 방법을 찾고 있었고 아래 (C99)를 사용해야합니다. 이를 통해 일반 유형과 동일한 방식으로 단일 구조 또는 구조 배열을 초기화 할 수 있습니다.

typedef struct {
    char *str;
    size_t len;
    jsmntok_t *tok;
    int tsz;
} jsmn_ts;

#define jsmn_ts_default (jsmn_ts){NULL, 0, NULL, 0}

이것은 코드에서 다음과 같이 사용될 수 있습니다.

jsmn_ts mydata = jsmn_ts_default; /* initialization of a single struct */

jsmn_ts myarray[10] = {jsmn_ts_default, jsmn_ts_default}; /* initialization of
                                                    first 2 structs in the array */

그러나 이것은 구조 배열을 기본값으로 초기화하지 않습니다. 배열의 첫 번째 구조를에 제공된 값 jsmn_ts_default으로 초기화하지만 나머지 구조는 배열에 정적 저장 기간이있는 것처럼 초기화되므로 멤버가 NULL및 로 초기화됩니다 0. 그러나 변경 #define jsmn_ts_default (jsmn_ts){"default", sizeof "default", NULL, 0}하면 첫 번째 배열 요소 만 초기화됩니다.
전 nihilo

그래, 난 그냥 편집에 포스트를 원 더 많은 테스트에서 온은 : BTW, 같은 동작이 함께 일어나는 int a[10] = {1};것입니다 만 1 요소==1
div0man
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.