7-3-다.선언과 정의

이쯤에서 선언과 정의에 대해 구분해 보자. 아주 비슷한 용어인 것 같지만 달라도 한참 다르며 다소 헷갈리는 용어라 정리가 필요하다. 일단 도표로 선언과 정의의 특성을 정리해 보자.

 

 

역할

메모리

정보의 완전성

중복 가능성

선언

알린다.

사용 안함

불완전해도

가능

정의

생성한다.

할당

항상 완전해야

불가능

 

선언과 정의의 대상이 되는 것에는 함수, 변수, 타입, 매크로, 태그 등 여러 가지가 있으나 주로 함수와 변수가 주 대상이다.

 

선언(Declaration) - 컴파일러에게 대상에 대한 정보를 알린다. 함수가 어떤 인수들을 전달받으며 어떤 타입을 리턴하는지를 알리는 원형 선언이 대표적인 선언이다. 컴파일러에게 정보만 제공하는 것이므로 본체를 가지지 않으며 실제 코드를 생성하지도 않는다. 그래서 다음처럼 여러 번 중복되어도 상관없다.

 

int Max(int a, int b);

int Max(int a, int b);

 

물론 똑같은 내용을 일부러 이렇게 중복 선언할 경우는 없겠지만 헤더 파일을 여러 번 포함하다 보면 중복 선언될 경우가 있다. 이렇게 본의 아니게 중복 선언되더라도 문제는 없다. 단, 중복 선언할 경우 앞의 선언과 뒤의 선언이 달라서는 안된다. 앞에서는 int Max(...); 로 선언해 놓고 다시 선언할 때는 double Max(...)로 선언할 수는 없다.

정의(Definition) - 대상에 대한 정보로부터 대상을 만든다. int i; 정의문에 의해 4바이트를 할당하며 int Max(int, int) { } 정의로부터 함수의 본체를 컴파일하여 코드를 생성한다. 정의는 변수의 타입, 함수의 인수 목록을 컴파일러에게 알려 주기도 하므로 항상 선언을 겸한다. 그래서 함수를 호출부보다 더 앞쪽에서 정의하면 컴파일러가 이 함수의 본체를 만들면서 모든 정보를 파악할 수 있으므로 별도의 원형 선언을 하지 않아도 된다.

정의는 실제 대상을 만들어 내기 때문에 중복되어서는 안된다. 전체 프로그램을 통해 단 한 번만 나타나야 하며 두 번 이상 중복할 필요도 없다. 만약 정의를 두 번 반복하면 컴파일러는 왜 똑같은 함수를 두 번 정의하느냐는 에러 메시지를 출력할 것이다.

 

이렇듯 선언과 정의는 분명히 다른 용어이지만 실제로는 명확하게 구분하지 않고 대충 사용하는 경향이 있다. 지역변수의 경우 정의와 선언이 완전히 일치하며 만든 영역에서만 사용하므로 별도의 선언을 할 수도 없고 할 필요도 없다. 그래서 지역변수는 정의만 가능한 대상이지만 일반적으로 "선언한다"라고 하지 "정의한다"라고는 하지 않는다. 전역변수의 경우는 int i;가 정의이고 extern int i;가 선언으로 분명히 구분되지만 관습적으로 전역변수 정의문인 int i; 도 선언문이라고 부른다.

매크로의 경우도 실제 메모리를 할당하는 것은 아니므로 선언이 맞지만 일반적으로 정의라고 표현한다. 매크로를 정의하는 명령어가 #define이지 #declare가 아닌 것만 봐도 그렇다. typedef에 의한 사용자 정의 타입도 키워드에 def라는 단어가 포함되어 있기는 하지만 원칙적으로 선언이라는 용어가 옳다. 그러나 표준 문서에서 조차도 typedef를 사용자 선언 타입이라고는 표현하지 않으며 타입을 정의한다고 표현한다. 구조체나 열거형의 태그는 주로 선언한다고 하지만 가끔 정의한다는 표현을 쓰기도 한다. 이렇듯 두 용어는 분명히 다르지만 실제로는 별 구분없이 사용되는 경향이 있다.