이번글은 저희같은? 사용자가 C++코드를 작성할 때 왜 헤더파일과 cpp파일로 나누어서 코드를 작성하는 지에 대한 글입니다.
저또한 그냥 아무런 이해없이 남들이 다 그렇게 쓰니까 아무생각없이 썻었는데
inline이나 템플릿을 공부하면서 부터 꼬이기 시작해서 다시 C++의 Build Process부터 공부한뒤 이해한 내용을 정리하였습니다.
Build Process
C++의 빌드 프로세스는 크게 아래 세가지 단계로 순자적으로 진행이 됩니다.
- PreProcess
- Compile
- Link
우분투 환경에서 main.cpp, hello.cpp만들고 아래와 같이 코드를 작성해주도록 하겠습니다.
요로코롬 나누어서 컴파일 한뒤 실행하면 당연히 컴파일 자체가 안됩니다.
너무나도 당연하게 main.cpp에서 Hello라는 함수의 선언도 없고 정의도 없기 때문입니다.
그럼 위처럼 main.cpp에 선언을 해준 경우에는 컴파일 될까요??
네! 컴파일은 문제없이 진행됩니다!
다만 "링킹 에러"가 발생합니다.
위처럼 컴파일은 되었지만 링킹에러가 발생하는데요...
일단 컴파일은 되었습니다. 그말은 "오브젝트 파일"이 생성되었다라는 의미입니다.
그리고 오브젝트 파일을 가지고 "실행 파일"을 만들려고하는 과정 Hello라는 "function call"을 찾을 수 없기 때문에 발생한 문제입니다.
그래서 g++ main.cpp -c -Wall -Werror 명령어를 통해 main.cpp의 오브젝트 파일을 생성해보도록 하겠습니다.
원래는 이상한 하늘색 글씨로 보이네요... 사실 제 이것은 제 vim이 깨져서 이렇게 보이고 원래는 사람이 이해못하는 숫자로 가득채워져 있습니다.
그럼 이 오브젝트파일을 어셈블리로 코드를 뽑아내서 사람이 그래도 어느정도 이해할 수 있도록 변경해보도록 하겠습니다.
어셈블리로 변환뒤에 해당파일을 보니 에셈블리를 잘 모르긴하지만 눈대중으로 때려 맞춰서 보면은 7번째 줄이 main함수를 가르키는 거 같고 16번째 줄에서 function을 call하는 거 같군요...
근데 Hello라는 함수를 호출을 안하고 _Z5Hellov@PLT?라는 이상한 함수를 호출하네요..
이렇게 쓰인 이유는 "function mangling" 때문입니다.
즉, 아무튼 맹글링 된 함수를 호출하는데 이 Hello라는 함수가 어디에 있는지 알 수가 없기때문에 링킹과정이 실패를 한 것입니다. 그럼 Hello함수를 찾게 해줄려면 hello.cpp파일을 컴파일 하여 오브젝트 파일을 만들면 해당파일을 찾을 수 있습니다.
그래서 hello.cpp의 목적파일을 만들고 main.o, hello.o를 링크하여 실행파일 만드는 과정을 보여드리겠습니다.
두 파일간에 #include를 사용하지 않고 목적파일을 만들어서 이들을 링킹하여 실행파일을 만들어 냈습니다.
위는 hello.cpp를 컴파일하여 나온 목적파일을 어셈블리로 변환한 부분입니다.
위는 main.cpp 목적파일의 어셈블리 부분입니다. 이렇게 목적파일에 대한 부분이 있기 때문에 링킹과정에서 문제없이 엔트리 포인트를 찾아내 실행파일을 만들 수 있었습니다.
위처럼 파일의 상단부에 함수에 대한 선언을 해주게 되는데 선언수는 제한이 없습니다.
다만 ODR에 의해 일반 함수의 경우 전체 프로젝트에서 오직 하나만 존재해야합니다.
ODR에 대한 내용은 https://modoocode.com/320 이곳을 참고해주세요ㅎㅎ
아무튼 이렇게 선언이 중복되다 보니 cpp파일에 중복되는 선언 부분을 "헤더 파일에 옮겨 줍니다.
이렇게 헤더에 옮기게 되면은 선언을 중복없이 전처리기 #include를 사용하여 선언부를 관리할 수 있습니다.
위처럼 hello.h라는 헤더파일을 만들고 이곳에다가 void Hello()라는 함수를 선언해줍니다.
그리고 hello.cpp와 main.cpp에서는 함수를 선언하는 것 대신에
hello.h 헤더파일을 include해주기만 하면됩니다. 만약 hello.cpp에 함수가 100개 있었다면 main.cpp에서는 100개에 대한 함수를 모두 전방선언 해야되겠지만 (100개를 다 사용한다는 가정하에) 이렇게 헤더와 cpp파일을 구분하여 선언부만 main.cpp에서 include하게 될 경우 모든 선언부를 가져와 쓰기만 하면됩니다!!ㅎㅎ
실제 구현부는 링킹과정에서 링크 되겠지요.
컴파일과 실행도 잘 되는 것을 확인했습니다.
정리하자면
"아 난 링킹같은 복잡한거 모르겠고, 선언만 해서(inlcude만해서) 뭔지만 알려준다음에 컴파일만 되게 어떻게 해줄게! 링킹은 링커 니가해라!"
이정도 겠네요 ㅎㅎ
감사합니다 :)
참고한 자료
https://www.youtube.com/watch?v=QAxjN0KUaLo
'CPP' 카테고리의 다른 글
[C++] boost 라이브러리 설치 방법 (0) | 2023.08.17 |
---|---|
[C++] constexpr (0) | 2023.08.17 |
[C++] stream buffer와 표준 입출력 (0) | 2023.08.02 |
[C++] 전달참조 (0) | 2023.07.31 |
[C++] 오른값 참조 (0) | 2023.07.30 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!