아래 코드가 있다 치자.
#include <iostream>
int add(int x, int y); // forward declaration of add() using function prototype
int main()
{
int tmp = add(3,4);
return 0;
}
// note: No definition for function add
뭔 이상한 코드가 다 있나 할 것이다.
prototype declaration 만 있을 뿐, add함수의 body는 어디에도 선언되어있지 않다.
컴파일될까?
된다!
심지어 7번줄의 add 호출문도 어셈블리 7번줄처럼 add 심볼을 찾아 branch 뛰라고 적혀있다.
다만, add 심볼은 정작 어셈블리 어디에도 적혀있지 않다.
그것은, compile 의 역할은 딱 "각 file을 independently 하게 asm(.o)으로 바꾸고, .o에 숨어있는 심볼들 짜맞추기는 링커가 전담한다"로 링커와 컴파일러가 분업되어있기 때문이다.
즉, 위 코드는 컴파일이 된다. 그러나 링크가 안된다.
여기서 두 가지 사실을 알 수 있다.
1. Declaration은 한 program 내에서 여러 번 선언가능. 한 file 내에서는 여러 번 불가능.
2. Definition은 한 program 내에서 단 1번 선언가능.
따라서, 자연스럽게 코더는 이렇게 프로그램을 짜게 된다.
1. Declaration은 .h에 단 한 번 작성.
2. Definition은 .cpp에 단 한 번 작성.
3. .cpp가 필요한 경우, .h를 #include 한다. 이 때, Declaration은 program 전체에는 여러번 등장해도 되므로 문제가 발생하지 않는다.
주의: .h는 여러 cpp에서 끌어쓸 수 있다.
따라서, .h 안에 구체적인 Definition 이 포함된다면, 99%의 확률로 링크 에러가 발생한다.
따라서, .h에는 순수하게 "Declaration" 만 포함토록 하자.
Declaration의 반대이다.
멤버변수, size까지 상세히 기술된 것이다.
선언과 달리, Definition은 한 file 내에 중복시 compile error, 한 program 내 중복시 linker error 를 낸다.
즉 중복선언 안된다.
함수는
int foo(int a);
하면 Declaration으로 취급된다.
즉,
#include <iostream>
int add(int x, int y); // forward declaration of add() using function prototype
int add(int x, int y); // forward declaration of add() using function prototype
int main()
{
int tmp = add(3,4);
return 0;
}
// note: No definition for function add
해도 컴파일 된다.
ODR을 어기지 않았기 때문이다.(Declaration != Definition)
반면에 함수와 달리, 변수는
int a;
하면 Definition으로 취급된다.
이것이
int main(){
int a; // DEFINITION
int a; // DEFINITION TWICE -> THUS ERROR!
return 0;
}
에서 에러가 발생하는 이유이다. One Definition Rule(이하 ODR)을 어기기 때문이다.
단, extern 으로 선언된 변수는
extern int a;
해도 Declaration으로 취급된다.