언어/C&C++ 기본

[C++] Compiler

차가운오미자 2021. 6. 14. 18:31

* 다음 강의 내용을 정리한 것

https://www.youtube.com/watch?v=3tIqpEmWMLI&list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb&index=6

Compile

C++은 파일에 대해서 신경쓰지 않는다. (자바는 디렉토리랑 파일명을 프로그램 작성자가 명시해줘야 한다. 예를 들어서 class이름은 파일명이랑 같아야 한다는 점) 코드를 작성하는 사람이 컴파일러에게 이 파일이 어떤 파일이며, 이걸 어떻게 다뤄야 할지를 직접 알려줘야 한다.

예를 들어 파일 확장자를 cpp로 하면 컴파일러에게 이걸 cpp 파일이라고 이해하고 다뤄라하고 알릴 수 있음

Translation Unit

컴파일러는 번역을 단위 별로 실행하는데, 컴파일러가 번역하는 단위를 translation unit이라고 부른다. 또 다르게 표현하자면 c/c++ 컴파일러가 받는 최종적인 input이라고 볼 수 있다. 일반적으로 전처리기가 처리한 소스파일을 의미한다. 전처리기가 원래 소스파일에 include한 소스들을 포함하고, 그 외 ifndef 등이 포함된 걸 하나로 딱 처리한 것.

 

 참고: https://en.wikipedia.org/wiki/Translation_unit_(programming)

Translation unit (programming) - Wikipedia

Translation unit (programming) From Wikipedia, the free encyclopedia This article is about the C and C++ programming term. For the linguistic meaning of the term, see translation unit . This article needs additional citations for verification . Please help improve this article by adding citations to...

en.wikipedia.org

Preprocessing(전처리)

statement types: include, define, if and ifdef

#include: just copy and paste

예를 들어, function에 } 을 마지막에 안붙이고, endbracket.h 파일에 } 하나만 넣고 저장한 후에 function끝에 } 대신에 #include "endbracket.h"만 해줘도 정상적으로 컴파일 됨

Properties에 가서 Configuration Properties > C/C++ > Preprocessor 에서 "Preprocess to a file"을 "yes" 로 설정해주면 컴파일 후에 main.i 라는 파일이 생긴 걸 확인할 수 있다. 이 파일을 열어보면 어떻게 헤더 파일이 include되어 있는지 확인할 수 있다. (대신 이에 대응되는 obj 파일이 안생긴다!)

 

#define

#define INTEGER int 하면 INTEGER이라고 되어 있는걸 다 int로 대체하게 됨

 

#if 와 #endif​

if문에 따라서 #if와 #endif​사이에 있는 코드를 포함하거나 제외한다.

#ifdef

만약에 ~가 정의되어 있다면 실행, 아니면 실행 x

if A여서 A 가 거짓이라도 정의만 되어 있으면 실행한다.

참고) https://jhnyang.tistory.com/299

 

Opitmization

이 obj 파일은 바이너리로 되어 있어서 열어보면 바이너리 코드로 되어 있다.

이 코드를 어셈블리어로 보고 싶으면, Properties > c/c++ > Output Files에서 Assembler Output을 No Listing 에서 Aseembly-Only-Listing로 바꿔준다. 그러고 컴파일 하면 어셈블리어로 된 파일을 만날 수 있다. (extension: .asm)

* Optimization 필요성

예를 들어서, 추가적으로 컴파일러가 하는 optimization을 좀 살펴보자면 코드가

int multiply(int a, int b){
    int result = a*b;
    return result;
}

로 되어 있을 때, 어셈블리어로 변환된 코드를 보면 불필요하게 레지스터에 저장하는 것들이 나온다. (바로 return a*b를 하면 발생하지 않을 mov 명령들) -> 이런 걸 줄이기 위해서 optimization이 필요한 것이다.

 

디버그 모드에서 optimization을 해보기 위해서 컴파일 옵션들을 좀 바꿔보자면,

똑같이 Properties > C/C++ >Optimiation 에 가서 Configuration이 Debug로 맞춰져있는지 한 번 보고, 밑에 Optimization을 maximize speed로 설정해보자. 그러면 오류가 뜨기 때문에 Code generation에서 Basic Runtime Checks 를 Default로 바꿔준다. (이렇게 하면 런타임 체크를 생략하게 됨)

그러고 다시 어셈블리 파일을 보면 훨씬 간단하게 바뀌어 있다.

 

 

+ Constant folding

예를 들어 코드가

return 2*5;

 

로 되어 있으면, 이걸 최적화 컴파일 한 후에 어셈블리 코드를 보면

mov eax 10

으로 되어 있는 것을 확인할 수 있다. 단순 상수 곱셈이니까, 컴파일러가 그냥 곱해서 10을 저장해라라는 식으로 어셈블리어를 생성해둔 것. 이런 걸 constant folding 이라고 부른다.

 

다른 함수를 콜하는 main 파일까지 만들어서 컴파일해보면 call 함수명@@whatever 이렇게 해서 다른 obj 파일에 있는 함수를 불러오곤 하는데, 이 @@ 뒤에 있는 것들은 링커가 함수들을 찾아내기 위해 쓰는 사인이라고 생각하면 된다. (일단 그렇게 이해)

 

'언어 > C&C++ 기본' 카테고리의 다른 글

[C++] Class  (0) 2021.06.25
[C++] Header Files  (0) 2021.06.14
[C++] Variables, Functions, Pointers, References  (0) 2021.06.14
[C++] Linker  (0) 2021.06.14
[C++] How C++ Works  (0) 2021.06.14