초기화
초기화 (initialization)
객체를 선언할 때 그 객체의 시작 값을 함께 지정해 주는 과정을 초기화라고 해요. C에서는 초기화를 생략하면 어떤 값이 들어가는지도 시점에 따라 달라지는데, 이 동작을 이해해야 예상 밖의 값과 싸우지 않아요.
출처: cppreference
본문
객체의 선언은 초기화 라는 과정을 통해 그 초기의 값을 제공할 수 있어요.
각 선언자(declarator)에 대해, 초기화자(initializer)를 생략하지 않으면 다음 중 하나가 될 수 있어요:
= expression |
(1) | |
= { initializer-list } |
(2) | |
= { } |
(3) | (C23부터) |
여기서 initializer-list는 비어 있지 않은 초기화자들의 쉼표로 구분된 목록(선택적 후행 쉼표 허용)이고, 각 초기화자는 다음 세 가지 형태 중 하나예요:
| expression | (1) | |
{ initializer-list } |
(2) | |
{ } |
(3) | (C23부터) |
designator-list = initializer |
(4) | (C99부터) |
여기서 designator-list는 [ constant-expression ] 형태의 배열 지정자나 . identifier 형태의 구조체·공용체 멤버 지정자의 목록이에요. 자세한 내용은 배열 초기화와 구조체 초기화 문서를 참고하면 돼요.
참고: 초기화자 외에도, 중괄호로 감싼 initializer-list는 복합 리터럴(compound literal)에서 나타날 수 있어요. 이것은 다음과 같은 형태의 표현식이에요:
( type ) { initializer-list } |
||
( type ) { } |
(C23부터) |
(C99부터)
설명
초기화자는 객체에 저장될 초기 값을 지정해요.
명시적 초기화
초기화자가 제공되면 다음을 참고해요:
- 스칼라 타입의 초기화는 스칼라 초기화
- 배열 타입의 초기화는 배열 초기화
- 구조체·공용체 타입의 초기화는 구조체 초기화
암시적 초기화
초기화자가 제공되지 않으면:
- 자동 저장 기간(automatic storage duration)을 가진 객체는 불확정 값(트랩 표현일 수도 있음)으로 초기화돼요.
- 정적·스레드 지역 저장 기간을 가진 객체는 빈 초기화(empty-initialized)돼요.
빈 초기화
| 객체가 = {} 초기화자로부터 명시적으로 초기화되면 빈 초기화된 것이에요. | (C23부터) |
어떤 경우에는 객체가 명시적으로 초기화되지 않아도 빈 초기화됩니다:
- 포인터는 자기 타입의 널 포인터 값으로 초기화돼요.
- 정수 타입의 객체는 부호 없는 0으로 초기화돼요.
- 부동소수 타입의 객체는 양의 0으로 초기화돼요.
- 배열의 모든 요소, 구조체의 모든 멤버, 공용체의 첫 멤버가 재귀적으로 빈 초기화되고, 모든 패딩 비트는 0으로 초기화돼요.
(널 포인터 값과 부동소수 0이 모두 모든 비트가 0인 표현을 갖는 플랫폼에서는, 정적 객체의 이 초기화 형태가 보통 프로그램 이미지의 .bss 섹션에 할당하는 방식으로 구현돼요.)
참고
정적·스레드 지역 저장 기간의 객체를 초기화할 때는 초기화자의 모든 표현식이 상수 표현식 또는 문자열 리터럴이어야 해요.
초기화자는 불완전 타입, 가변 길이 배열(VLA), 그리고 연결을 가진 블록 스코프 객체의 선언에는 사용할 수 없어요.
C의 값 초기화에 해당하는 전용 구성은 없어요. 하지만 = { 0 }(복합 리터럴에서는 ( T ){ 0 })(C99부터)로 대신할 수 있어요. C 표준은 빈 구조체·빈 공용체·길이 0의 배열을 허용하지 않기 때문이에요. |
(C23 이전) |
|---|---|
빈 초기화자 = {}(복합 리터럴에서는 ( T ){})를 사용하면 C++의 값 초기화와 같은 의미를 얻을 수 있어요. |
(C23부터) |
예제
초기화를 생략했을 때와 명시했을 때 값이 어떻게 달라지는지 확인해 볼게요. 지역 변수는 불확정 값이 되지만, 정적 변수는 0으로 초기화된다는 차이를 기억하면 좋아요.
#include <stdlib.h>
int a [ 2 ]; // initializes a to {0, 0}
int main ( void )
{
int i ; // initializes i to an indeterminate value
static int j ; // initializes j to 0
int k = 1 ; // initializes k to 1
// initializes int x[3] to 1,3,5
// initializes int* p to &x[0]
int x [] = { 1 , 3 , 5 }, * p = x ;
// initializes w (an array of two structs) to
// { { {1,0,0}, 0}, { {2,0,0}, 0} }
struct { int a [ 3 ], b ;} w [] = {[ 0 ]. a = { 1 }, [ 1 ]. a [ 0 ] = 2 };
// function call expression can be used for a local variable
char * ptr = malloc ( 10 );
free ( ptr );
// Error: objects with static storage duration require constant initializers
// static char* ptr = malloc(10);
// Error: VLA cannot be initialized
// int vla[n] = {0};
}
더 알아보기
- 스칼라 타입의 초기화는
scalar initialization문서에서 확인할 수 있어요. - 배열 초기화는
array initialization, 구조체·공용체는struct initialization문서를 참고해요.