Struct and union initialization
초기화 과정에서 struct 또는 union 타입의 객체를 초기화할 때, 초기화자는 반드시 비어 있지 않은 (C23 이전) 중괄호로 묶인 멤버 초기화자들의 쉼표로 구분된 목록이어야 합니다:
=
{
expression
,
...
}
|
(1) | (C99 이전) | |||||||
=
{
designator
(선택적)
expression
,
...
}
|
(2) | (C99 이후) | |||||||
=
{
}
|
(3) | (C23 이후) | |||||||
여기서
designator
는
.
member
형태의 개별 멤버 지정자와
array designators
형태인
[
index
]
의 인접 또는 공백으로 구분된 시퀀스입니다.
명시적으로 초기화되지 않은 모든 멤버는 empty-initialized 됩니다.
목차 |
설명
union 를 초기화할 때, 초기화 목록은 반드시 하나의 멤버만 가져야 하며, 이는 지정된 초기화자를 사용하지 않는 한 (C99부터) union의 첫 번째 멤버를 초기화합니다.
union { int x; char c[4]; } u = {1}, // u.x를 활성화하여 값 1을 가짐 u2 = { .c={'\1'} }; // u2.c를 활성화하여 값 {'\1','\0','\0','\0'}을 가짐
구조체를 초기화할 때, 목록의 첫 번째 초기화자는 첫 번째로 선언된 멤버를 초기화합니다 (지정자가 명시되지 않는 한) (C99부터) , 그리고 모든 후속 초기화자들은 지정자 없이 (C99부터) 이전 표현식으로 초기화된 멤버 다음에 선언된 구조체 멤버들을 초기화합니다.
struct point {double x,y,z;} p = {1.2, 1.3}; // p.x=1.2, p.y=1.3, p.z=0.0 div_t answer = {.quot = 2, .rem = -1 }; // div_t 내 요소들의 순서는 달라질 수 있음
|
지정자는 이후 초기화자가 지정자가 기술한 구조체 멤버를 초기화하도록 합니다. 초기화는 지정자가 기술한 멤버 다음에 선언된 요소부터 선언 순서대로 계속 진행됩니다. struct {int sec,min,hour,day,mon,year;} z = {.day=31,12,2014,.sec=30,15,17}; // initializes z to {30,15,17,31,12,2014} |
(C99부터) |
초기화자의 수가 멤버 수보다 많으면 오류입니다.
중첩 초기화
구조체 또는 공용체의 멤버가 배열, 구조체 또는 공용체인 경우, 중괄호로 묶인 초기화 목록에서 해당 멤버에 대한 유효한 초기화자는 다음과 같이 중괄호를 생략할 수 있다는 점을 제외하고 해당 멤버에 유효한 모든 초기화자입니다:
중첩된 초기화자가 여는 중괄호로 시작하는 경우, 해당 닫는 중괄호까지의 전체 중첩 초기화자는 해당 멤버 객체를 초기화합니다. 각 왼쪽 여는 중괄호는 새로운 현재 객체 를 설정합니다. 현재 객체의 멤버들은 자연스러운 순서로 초기화됩니다 (지시자가 사용되지 않는 한) (C99부터) : 배열 요소는 첨자 순서로, 구조체 멤버는 선언 순서로, 모든 공용체의 첫 번째로 선언된 멤버만 초기화됩니다. 닫는 중괄호에 의해 명시적으로 초기화되지 않는 현재 객체 내의 하위 객체들은 빈 초기화 됩니다.
중첩된 초기화자가 여는 중괄호로 시작하지 않는 경우, 멤버 배열, 구조체 또는 공용체의 요소나 멤버를 설명하기 위해 목록에서 충분한 초기화자만 가져옵니다; 남은 초기화자는 다음 구조체 멤버를 초기화하는 데 사용됩니다:
struct example ex = {80, 127, 0, 0, 1}; // 80은 ex.addr.port를 초기화합니다 // 127은 ex.in_u.a8[0]을 초기화합니다 // 0은 ex.in_u.a8[1]을 초기화합니다 // 0은 ex.in_u.a8[2]을 초기화합니다 // 1은 ex.in_u.a8[3]을 초기화합니다
|
지정자가 중첩된 경우, 멤버에 대한 지정자는 이를 감싸는 struct/union/array에 대한 지정자를 따릅니다. 중괄호로 묶인 초기화 리스트 내부에서 가장 바깥쪽 지정자는 현재 객체(current object) 를 참조하며, 현재 객체 내에서 초기화할 하위 객체만을 선택합니다. struct example ex2 = { // 현재 객체는 ex2, 지정자는 example의 멤버를 위한 것 .in_u.a8[0]=127, 0, 0, 1, .addr=80}; struct example ex3 = {80, .in_u={ // 현재 객체를 union ex.in_u로 변경 127, .a8[2]=1 // 이 지정자는 in_u의 멤버를 참조 } }; 어떤 하위 객체가 두 번 명시적으로 초기화되면(지정자를 사용할 때 발생할 수 있음), 리스트에서 나중에 나타나는 초기화자가 사용됩니다(이전 초기화자는 평가되지 않을 수 있음): 초기화되지 않은 모든 하위 객체는 암시적으로 초기화되지만, 하위 객체의 암시적 초기화는 초기화 리스트에서 이전에 나타난 동일한 하위 객체의 명시적 초기화를 절대 재정의하지 않습니다(올바른 출력을 보려면 clang을 선택하십시오):
이 코드 실행
#include <stdio.h> typedef struct { int k; int l; int a[2]; } T; typedef struct { int i; T t; } S; T x = {.l = 43, .k = 42, .a[1] = 19, .a[0] = 18 }; // x는 {42, 43, {18, 19} }로 초기화됨 int main(void) { S l = { 1, // l.i를 1로 초기화 .t = x, // l.t를 {42, 43, {18, 19} }로 초기화 .t.l = 41, // l.t를 {42, 41, {18, 19} }로 변경 .t.a[1] = 17 // l.t를 {42, 41, {18, 17} }로 변경 }; printf("l.t.k is %d\n", l.t.k); // .t = x는 l.t.k를 42로 명시적으로 설정 // .t.l = 41은 l.t.k를 암시적으로 0으로 만들었을 것 } 출력: l.t.k is 42 그러나 초기화자가 여는 중괄호로 시작할 경우, 해당 현재 객체 는 완전히 재초기화되며 이전에 명시적으로 초기화된 모든 하위 객체들은 무시됩니다: struct fred { char s[4]; int n; }; struct fred x[ ] = { { { "abc" }, 1 }, // x[0]을 { {'a','b','c','\0'}, 1 }로 초기화 [0].s[0] = 'q' // x[0]을 { {'q','b','c','\0'}, 1 }로 변경 }; struct fred y[ ] = { { { "abc" }, 1 }, // y[0]을 { {'a','b','c','\0'}, 1 }로 초기화 [0] = { // 현재 객체는 이제 전체 y[0] 객체 .s[0] = 'q' } // y[0]을 { {'q','\0','\0','\0'}, 0 }로 대체 }; |
(C99부터) |
참고 사항
초기화자 목록은 무시되는 후행 쉼표를 가질 수 있습니다.
struct {double x,y;} p = {1.0, 2.0, // 후행 쉼표 허용 };
|
C에서는 초기화자의 중괄호 목록이 비어 있을 수 없습니다 (C++에서는 빈 목록을 허용하며, 또한 C에서 struct 는 비어 있을 수 없음에 유의하십시오): |
(until C23) |
|
C++에서와 같이 C에서도 초기화자 목록이 비어 있을 수 있습니다: |
(since C23) |
struct {int n;} s = {0}; // OK struct {int n;} s = {}; // C23 이전까지 오류: 초기화 리스트가 비어 있을 수 없음 // C23 이후 OK: s.n이 0으로 초기화됨 struct {} s = {}; // 오류: 구조체는 비어 있을 수 없음
|
모든 저장 기간의 집합체를 초기화할 때 초기화 목록의 모든 표현식은 상수 표현식 이어야 합니다. |
(C99까지) |
|
다른 모든 초기화 와 마찬가지로, 정적 또는 스레드 지역 (C11부터) 저장 기간 의 집합체를 초기화할 때 초기화 목록의 모든 표현식은 상수 표현식 이어야 합니다: static struct {char* p} s = {malloc(1)}; // error 모든 초기화에서 부분 표현식들의 평가 순서 는 비결정적으로 순서 지정됩니다 (단 C++11 이후 C++에서는 아님): int n = 1; struct {int x,y;} p = {n++, n++}; // unspecified, but well-defined behavior: // n is incremented twice in arbitrary order // p equal {1,2} and {2,1} are both valid |
(C99부터) |
예제
|
이 섹션은 불완전합니다
이유: 더 실용적인 예시들, 아마도 일부 소켓 구조체들을 초기화하는 내용 |
#include <stdio.h> #include <time.h> int main(void) { char buff[70]; // 지정 초기화자는 멤버 순서가 지정되지 않은 구조체의 사용을 단순화합니다 // order of members is unspecified struct tm my_time = { .tm_year=2012-1900, .tm_mon=9, .tm_mday=9, .tm_hour=8, .tm_min=10, .tm_sec=20 }; strftime(buff, sizeof buff, "%A %c", &my_time); puts(buff); }
가능한 출력:
Sunday Sun Oct 9 08:10:20 2012
참고문헌
- C17 표준 (ISO/IEC 9899:2018):
-
- 6.7.9/12-39 초기화 (p: 101-105)
- C11 표준 (ISO/IEC 9899:2011):
-
- 6.7.9/12-38 초기화 (p: 140-144)
- C99 표준 (ISO/IEC 9899:1999):
-
- 6.7.8/12-38 초기화 (p: 126-130)
- C89/C90 표준 (ISO/IEC 9899:1990):
-
- 6.5.7 초기화
참고 항목
|
C++ documentation
for
Aggregate initialization
|