[C/C++] 선언(Declaration)과 정의(Definition)의 차이


* 본 글은 학부생의 눈높이에 작성되었습니다

 

int a;
int a = 10;

<ERROR>
오류	C2086	'int a': 재정의

위 코드를 Visual Studio 에서 실행해보면 int a가 재정의(redefinition) 됐다는 오류 메세지가 출력되면서 컴파일이 되지 않습니다. 이런 오류 메세지는 컴파일러마다 다른데 재정의가 아니라 재선언(redeclaration) 이라는 오류 메세지가 출력되기도 합니다.

 

과연 정의와 선언의 차이는 무엇일까요?

정의와 선언은 다양한 프로그래밍 자료에서 혼동되어 사용되는 단어긴 하지만 엄밀히 따지면 이 둘은 다른것 입니다. 오늘은 이에 대해 알아보겠습니다.

 

선언(Declaration) vs 정의(Definition)

모든 정의는 선언을 포함하고 있지만 모든 선언은 정의가 아니다.

즉 간단히 말해서 정의는 선언이라고 할 수 있지만 선언은 정의가 아니다.

 

우선 위 두 문장을 이해해봅시다. 위 문장을 쉽게 정리하면 모든 정의는 선언이라고 할 수 있지만 선언은 정의가 아닙니다. 명제 논리로 따져보자면 조건명제(Implication)와 비슷한 것인데

정의 → 선언 은 참이지만 선언 → 정의 는 거짓이라는 뜻입니다.

 

더 쉽게 이야기 하면 정의는 선언이니 어떤 변수의 정의문은 선언문이라고 할 수 있고 (정의와 동시에 선언문이라고 표현할 수 있습니다.), 정의문이 아닌 선언문이 있을 수 있으니 결국에 어떤 변수나 함수를 기술하는 것은 "선언" 이라는 표현으로 뭉뚱그려 표현할 수 있습니다.

 

그래서 어떤 글을 보면 선언과 정의가 뭉뚱그려 표현되는 것입니다.

정확히 하자면 정의로 뭉뚱그려 표현하면 안돼고 선언으로 뭉뚱그려 표현해야 합니다.

 

즉 어떤 변수나 함수를 기술 하는건 두가지 Case로 나눠볼 수 있습니다.

1. 어떤 변수나 함수를 "정의"하는 문장(정의와 동시에 선언이라고 할 수 있음)

2. 어떤 변수나 함수를 "선언"하는 문장 (선언문이나 정의문은 아님.)

 

이제 정의와 선언에 관계에 대해 알았고 정의의 개념에 대해 알아보겠습니다.

정의는 어떤 요소에 대해 완전히 기술한 선언문입니다.

아까 정의는 선언이라고 하였습니다, 그래서 선언문이라는 것으로 표현할 수 있는데

위 문장이 햇갈리시면 정의를 어떤 요소에 대해 완전히 기술한 문장이라고 생각하셔도 됩니다.

 

이제 예제를 보면서 한 번 이에 대해 익혀보겠습니다.

 

아래는 정의문 입니다. (정의와 동시에 선언인 것.)

int a = 7;
int b;
vector <double> v;
double sqrt(double) { . . . };
struct Point { int x; int y; };

함수의 경우에는 인자값을 명시해줄 뿐만 아니라 중괄호로 함수 내용까지 전부 채워줘야지 완전한 기술이라고 볼 수 있고, 구조체의 경우에도 이름뿐만이 아닌 멤버 변수까지 명시해줘야 정의입니다.

 

그러나 변수 정의엔 주의가 필요한데 int a = 7; 뿐만 아니라 int b; 라는 것처럼 초기값이 지정되지 않아도 정의로 칩니다. 이에 대한 이유로는 b라는 메모리 공간을 int b; 라는 문장 보다 더 잘 "정의" 할 수가 없습니다. 물론 초기값을 제공해주면 더 좋은 정의겠지만 어쨌던 초기값이 없어도 정의입니다.

 

vector <double> v; 와 같은 것도 마찬가지 입니다.

어찌됬건 위 문장들은 정의와 동시에 선언인 것 입니다.

 

아래는 선언문 입니다. (정의문은 아님)

double sqrt(double);
struct Point;
extern int a;

아까도 말했듯이 sqrt 함수인데 내부 코드가 비어있어서 완전히 기술되어 있지 않습니다. 이런건 선언문입니다. 구조체도 멤버 변수가 완전히 기술되어야 정의라고 하였죠? 지금은 멤버 변수가 없으니 선언문입니다.

 

또한 extern int a; 와 같은 문장은 외부 변수(extern 키워드)를 가져오는 부분인데 요새는 잘 사용되지 않는 내용입니다. 저 문장은 아마 C언어를 조금 깊게 공부하셨다면 아실 수 있을건데 a라는 변수가 어떤 외부 파일에 있다고 단순히 컴파일러에게 알려주는 것으로, 역시 선언하는 것입니다. a라는 변수를 정의하는 것이 아닙니다.

 

선언은 여러번 할 수 있지만 정의는 그렇지 않다.

위 말대로 선언은 완전한 문장이 아니기 때문에 여러번 선언문을 실행해도 컴파일 오류가 발생하지 않지만, 어떤 변수나 함수를 정의를 해서 완전히 정의한 경우 정의를 2번 하면 컴파일 오류로 잡힙니다.

 

그게 글 초입에 소개했던 내용입니다. 그래서 C/C++에서 헤더 파일과 같이 여러 파일에서 #include 전처리기 문을 사용해서 가져와야 하는 경우 여러번 가져와도 문제가 없도록 헤더 파일엔 정의문이 아니라 선언만 적어주는게 권장되는 것 입니다. (보통 헤더 파일엔 함수 내용 없이 원형만 적으라고 배우는 내용이 바로 그것입니다. Class도 마찬가지이구요.. 사실상 반 강제입니다.)

 

컴파일러가 여러번 정의를 찾으면 얄짤 없이 redefinition 이나 double defenition 오류를 뱉지만 어떤 경우 redeclaration 오류를 뱉는 이유는 모든 정의는 선언이기 때문입니다.

(그러나 아까도 말했듯이 모든 선언문은 정의가 아닙니다...)

 

내용을 제대로 이해하셨으면 정의는 선언이고, (정의가 아닌) 선언문 2가지 케이스가 있으니 그냥 변수나 함수를 기술하는건 선언한다고 뭉뚱그려 표현 가능하단 것.. 이것만 제대로 이해하시고 기억하면 될 거 같습니다.

사실 아주 중요한 내용은 아닌데 학부 공부를 하다가 우연히 배우게 되어 정리합니다.

 

* 관점에 따라 정의와 선언에 대한 기술에 차이가 있을 수 있습니다. 본 글은 C++와 아래 참고문헌에 대한 내용을 기준으로 정리되었습니다.

 

 

 

<참고문헌>

Programming: Principles and Practice Using C++, 2nd edition, Bjarne Stroustrup

COMMENT WRITE