728x90

0. 분할되지 않은 기존 코드

→ 세 영역으로 나눌 수 있음

(1) main.cpp 소스파일 (2) func.cpp 파일 (3) struct.h 헤더파일

#include <iostream>
using namespace std;

/* 헤더 파일 */
/*구조체&함수 원형 선언*/
struct MyStruct {
    string name;
    int age;
};

void display(MyStruct&);

/* 소스 파일 */
/*main 함수*/
int main(){
    MyStruct sleepy = {"somuch", 23};
    display(sleepy);
    return 0;
}

/*함수의 body를 정의*/
void display(MyStruct &refer){
    cout << "이름: " << refer.name << endl;
    cout << "나이: " << refer.age << endl;
}

 


1. 헤더 파일 (struct.h)

- #define이나 const를 사용하는 기호 상수

- 구조체 선언

- 클래스 선언

- 템플릿 선언

 

- 함수 원형 (ex. void display(MyStruct&); 와 같이 원형을 선언해두는 곳이기도 함)

- 인라인 함수

 

→ reuse하고자 하는 덩어리들의 blueprint를 모아둔 곳

https://cognota.com/blog/the-importance-of-a-learning-blueprint-design/

//struct.h

/*ifndef~endif 기호상수화 */

#ifndef STRUCT
#include <iostream>
using namespace std;

/* 헤더 파일 */
/*구조체&함수 원형 선언*/
struct MyStruct {
    string name;
    int age;
};

void display(MyStruct&);
#endif

ifndef~endif 기호상수화

- STRUCT 덩어리가 이미 include되면, 그다음 같은 것이 호출되는 것을 무시할 수 있음
- 소스파일에서 특정 헤더 파일을 여러 번 호출하는 것이 원래 안 되는데
- 이로 인한 에러가 발생하는 것을 막기 위해, 헤더 파일에 ifndef~endif 구문을 사용함

 

 

2. 소스 파일 (main.cpp)

#include "struct.h"
#include "func.cpp"

/* 소스 파일 */
/*main 함수*/
int main(){
    MyStruct sleepy = {"somuch", 23};
    display(sleepy);
    return 0;
}

- #include "struct.h" 헤더를 반드시 불러와야 함 (전처리기와 관련된 것)

- Any command starting with a # in the first column is not a C/C++ statement, but rather a preprocessor

- Ther preprocessor performs very basic text-based substitutions (간단한 텍스트 대체 기능 수행)

- preprocessor가 처리한 결과물은 compiler로 보내짐

 

- 헤더파일에서 선언한 함수 / 기호 상수 / 구조체 / 클래스 / 템플릿 / 인라인 함수만이 → main에서 실행될 수 있음

- 실제로 '실행' 대상이 되는 함수

 

3. 함수 파일 (func.cpp)

//func.cpp
#include "struct.h"

/*함수의 body를 정의*/
void display(MyStruct &refer){
    cout << "이름: " << refer.name << endl;
    cout << "나이: " << refer.age << endl;
}

- 함수가 정의되어 있는 func.cpp는 마찬가지로, struct.h를 include 해와야 함

- func.cpp와 main.cpp를 직접 연결시키는 코드는 없음. 그러나 문제 없이 작동함.

**업데이트

- 만약 함수 선언을 위한 헤더파일과 & 함수 정의하는 func.cpp를 따로 분리시켰다면, main() 파일에서 func.cpp도 함께 include해야 오류를 방지할 수 있음. 그 이유는, Linker가 func.cpp에서 정의된 함수를 어셈블리 파일에 적절한 위치에 놓아야 하는데, main 파일에 "func.cpp"를 인클루드 한다는 코드가 없다면, 헤더에서 선언한 함수 정의를 찾는 데 문제가 생길 수 있음. (이하와 같은 에러)

 

ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

 

포함시키지 않아도 작동하는 경우가 있지만.. 오류에 대비하는 게 더 좋으니.


#상황

나(programmer): c++로 헤더파일(라이브러리)도 직접 만들었고~ main 소스파일에 불러왔고~ 이제 실행시켜야지~ !

 

#절차

Programmer: source code <* .cpp>를 작성함

Preprocessor(전처리기): 프로그래머가 작성한 소스코드를 컴파일러에게 전달하기 전, 컴파일 될 수 있는 상태로 준비(전처리)시킴

- 코드를 정리하고 필요한 부분을 추가하거나 변경

- 현재 소스 파일에서 include시킨 헤더 파일을 현재 코드에 포함시킴

- 매크로를 사용하여 특정 코드를 자동으로 대체함 (ex. #define 지시어를 사용하여 상수나 함수 호출을 자동으로 대체)

 

Compiler: 전처리된 코드를 받아서 실제 기계어로 번역하고 오류가 없는지 확인함.

 

Linker: 여러 개의 컴파일된 코드파일들을 하나로 합침.

컴파일된 파일과 라이브러리 파일들 간의 상호 의존성을 해결하고, 실행하는 파일의 메모리 주소를 조정함

 

Linker를 거친 후, 프로그래머가 작성한 코드 파일은 완전히 실행 가능한 상태가 됨~~~~~!~!

 

728x90

+ Recent posts