15. 소스 파일과 프로그램
15.1 분할 컴파일
파일은 전통적인 저장 단위이자, 컴파일 단위이다.
컴파일 단위가 하나의 파일인 경우, 해당 파일이나 해당 파일이 의존하는 무언가(아무리 조그맣더라도)에 하나라도 변경이 가해지면 파일 전체가 재컴파일돼야 한다. -> 프로그램 규모가 커진다면, 이러한 연관성을 판단하기가 어려워진다.
사용자는 소스 파일 (source file) 을 컴파일러에 제출한다. 그러면 해당 파일 전체가 전처리기에 의해 전처리된다. -> 매크로 처리가 진행되고, #include 지시자는 헤더를 가져온다. -> 전처기의 결과는 translation unit 으로 불리며, 해당 단위가 컴파일러의 작업 대상이자 C++ 언어 규칙에 의해서 기술되는 것이다.
링커는 별도로 컴파일 된 부분들을 함께 묶어주는 프로그램이다. -> 링커 작업은 프로그램이 시작되기 전에 완전히 끝날 수도 있고, 나중에 새로운 코드가 실행 중인 프로그램에 추가될 수 있다. (동적 링크)
15.2 링크 관계
file2.cpp g() 에 의해 사용되는 x 와 f() 는 file1.cpp 에서 정의된 것이다. 키워드 extern 은 file2.cpp 에 있는 x 의 선언이 선언일 뿐 정의가 아니라는 점을 나타낸다. -> x가 초기화 됐다면, 초기화 식을 가진 선언은 항상 정의의기 때문에, extern 은 무시되고 말 것이다. -> 개체는 프로그램에서 정확히 한 번 정의되어야 한다.
아래 코드는 다음과 같이 3개의 오류가 있다.
x는 두번 정의 되었다.
b는 다른 타입으로 두번 선언되었다.
c는 두번 선언되었지만 정의되지 않았다.
위와 같은 오류들은 단 하나의 파일만 살펴보는 컴파일러에 의해 탐지될 수 없다.
하지만 링커는 위 3가지 오류를 탐지할 수 있다.
네임스페이스 유효 범위에서 사용될 때 static 은 "다른 소스 파일에서 접근할 수 없다" 는 뜻이다. -> 링킹하지 않겠다는 의미
아래 코드에서 외부 링크 관계를 만들고 싶다면 다음과 같이 하면 된다.
다른 소스 파일에서 x1 에 접근하고 싶다면 stiatic 을 제거해야 한다.
x2 는 정의 앞에 extern 키워드를 붙여 주어야 한다.
inline 함수는 사용되는 모든 해석 단위에서 동일하게 정의되어야 한다. -> inline 함수는 컴파일 시간에 각각의 함수를 소스파일에 함수 내용을 삽입한다. (여기 까지는 문제가 안된다) -> 링커가 동작할 때 이름이 동일한 함수가 있기에 오류가 발생한다.
때문에, inline 함수는 헤더 파일에 정의해서 코드를 일관성 있게 유지해야만 한다.
기본적으로 const 개체, constexpr 개체, namespace 에서 static 으로 정의된 모든 것은 내부 링크 관계를 갖는다.
15.2.1 파일 로컬 이름
전역 변수는 유지 보수 문제를 일으킬 수 있기 때문에, 일반적으로는 피하는 편이 좋다. -> 특히 프로그램 내 어디에서 사용되는지 파악하기가 어렵고, -> 멀티스레드 프로그램에서는 엄청나게 찾기 어려운 버그를 낳는 데이터 경합의 원인이 될 수 있다.
15.2.2 헤더 파일
다른 해석의 단위에서 선언의 일관성을 달성하는 방법은 실행 코드나 데이터 정의가 포함된 소스 파일에 인터페이스 정보를 가진 헤더 파일을 #include 하는 것이다.
#include 매커니즘은 소스 프로그램 단편들을 하나의 컴파일 단위로 취합하기 위한 텍스트 조작 기능이다. -> 전처리기에 의해 동작한다.
아래 코드는 #include 가 등장하는 행을 to_be_include 파일의 내용으로 대체한다. -> to_be_include 의 내용은 컴파일러가 해독할 수 있는 C++ 소스 텍스트여야만 한다.
표준 라이브러리의 #include 는 <> 형태로 사용 가능하다.
...
Last updated