묻공러
[C++ NOTE] Compile Process
묻공러
묻지마공부
묻공러
전체
오늘
어제
  • 분류 전체보기 (535) N
    • C (54)
      • [코드조선] C 핵심 (35)
      • [언어본색] C 기초 (19)
    • C++ (72)
      • [루키스] C++ (9)
      • [루키스] 콜백함수 (6)
      • [루키스] STL (8)
      • [루키스] Modern C++ (11)
      • [노코프] C++ (10)
      • [노코프] Tips (16)
      • [일지] C++ (12)
    • C# (20)
      • [루키스] C# (9)
      • [루키스] 자료구조 (3)
      • [루키스] 실전 문법 (8)
    • 자료구조 & 알고리즘 (50)
      • [코드조선] C 자료구조 & 알고리즘 (6)
      • [합격자되기] C++ 코딩테스트 (12)
      • [루키스] C++ 자료구조 & 알고리즘 (32)
    • CS (69)
      • [널널한 개발자] CS 개론 (19)
      • [혼자 공부하는] 컴퓨터 구조 (16)
      • [혼자 공부하는] 운영체제 (18)
      • [널널한 개발자] 네트워크 (16)
    • 게임 그래픽스 (46)
      • [전북대] OpenGL (25)
      • [일지] DirectX (21)
    • 게임 엔진 - 언리얼 (123)
      • [코드조선] 언리얼 (53)
      • [코드조선] 언리얼 데디서버 (8)
      • [일지] 언리얼 (59)
      • [일지] 언리얼 (2) (3)
    • 게임 엔진 - 유니티 (28) N
      • [최적화] 유니티 (4)
      • [루키스] 유니티 (24) N
    • 게임 서버 (17)
    • 게임 수학 & 물리 (19)
      • 게임 수학 (12)
      • 게임 물리 (7)
    • GIT & GITHUB (4)
    • 영어 (18)
      • [The Outfit] 대본 공부 (11)
      • the others (7)
    • 그 외 (14)
      • In (5)
      • Out (5)
      • Review (4)

인기 글

최근 글

hELLO · Designed By 정상우.
C++/[노코프] C++

[C++ NOTE] Compile Process

2024. 3. 25. 12:03

01.Build Introduction
# 과정

Pre Processor 과정부터 Linker 과정 까지를 Compile이라고 부른다


# 대표 컴파일러 종류

Visual C++

gcc

clang

 



02.Header file

선언부는 헤더 파일에

구현부는 cpp파일에 넣어주는 것이 일반적이다

 



03.PreProcessor
전처리 과정에서는

#include, #define, #ifdef, #pragma once와 같은

#을 사용한 부분들을 복사 & 붙여 넣기를 통해 처리한다

 

여러 파일들이 생성되고

서로 헤더파일을 참조하다 보면,

전처리 과정에서 include 중복이 발생하는데 이를 막아주기 위해서는
모든 헤더파일 위에 #pragma once를 작성하면 된다

 

C++에서는 최대한 define 문법을 사용하지 않는 것이 좋다

define을 대체하는 방법으로는

constexpr과 if constexpr

혹은 C++ STL <limits>를 활용하는 방법이 있으며 아래와 같다

#include <iostream>
#include <limits>

//#define MAX_UINT16 65535
//#define MAX(a, b)	(((a) > (b)) ? (a) : (b))
//#define ABCD	2

constexpr int ABCD = 2;

int main()
{
	std::cout << std::numeric_limits<uint16_t>::max() << std::endl;
	std::cout << std::max(10, 100) << std::endl;

	if constexpr (ABCD)
	{
		std::cout << "Y";
	}
	else
	{
		std::cout << "N";
	}
}

 

 

 


 

04. Extern & Static
Extern은 
외부에 선언되어 있음을 알려주는 것이고

함수는 extern이 암시적으로 생략되어 있다

 

Static은

함수 혹은 변수가 해당 파일 혹은 해당 트랜스레이션 유닛 밖에서

사용하지 못하도록 막기 위해 사용한다 

 



05. Assembly
1) 곱셈보다 비트 시프트를 쓰면 속도가 빠르다는 말은 거짓이다 (똑같다)

unsigned int num8x(unsigned int a)
{
	return a * 8;
}

unsigned int num8x_2(unsigned int a)
{
	return a << 3;
}

 

2) 연산 처리 속도는 라인 수와 무조건 비례하진 않는다

int divide(int a, int b)
{
	return a / b;
}

int divideBy13(int a)
{
	return a / 13;
}

idiv가 imul보다 5배 정도 클럭이 더 필요하다

그래서 실제 라인 수는 아래가 더 길지만

시간은 아래가 더 빨리 처리된다

 

3) 컴파일러마다 효율이 다르다

int test (int a)
{
	if (a == 0) return a * 0;
	else if (a == 1) return a;
	else if (a == 2) return a / 4;
	else if (a == 3) return 5;
	
	return 0;
}

int test2 (int a)
{
	switch (a)
	{
		case 0: return a * 0;
		case 1: return a;
		case 2: return a / 4;
		case 3: return 5;
		default: return 0;
	}
}

 

 



06. Debug
디버그를 할 때는

Variable, Break Pointer, Call Stack (Back trace)을 적극 활용하면 된다

 



07. Library

1) Header Only Library

#include 헤더를 추가하고 있는 라이브러리라면

모두 이렇게 부를 수 있다

 

2) Static Library

.lib, .a 확장자이고

Link time에 바인딩이 된다

 

3) Dynamic Library

.dll, .so 확장자이고

Load time이나 Rutime에 바인딩이 된다

Load time은 프로그램이 실행되고 Loader가 프로세스를 실행시킬 때, 같이 바인딩되고

Rutime은 실행 도중에 바인딩된다

 

# Static Library

obj파일들을 하나의 파일인 static library file로 만들고 이를 아카이브라고 부른다
그리고 해당 static library file에서 필요한 부분들만 선택 및 재배치하고
링크 과정을 거친다
결국은 static library는 obj파일들을 모은 하나의 파일에 불과하다

 




08. Dynamic Library (Shared Library)
Dynamic Library는 Load time 혹은 Runtime에 바인딩이 된다


1) Load time
오브젝트 파일을 만들 때, fPIC라는 옵션을 설정해 주면

PIC로 설정된 오브젝트 파일들을 모아서

하나의 Dynamic Library를 만들게 된다

그리고 실행파일에서는 Dynamic Library의 내용은 포함되지 않고

Load time에 해당 Dynamic Library가 바인드 된다

 

PIC(Position Independent Code)는  
absolute base address를 relative base address로 바꿔서

각각의 다른 애플리케이션들에서 다이나믹 라이브러리와 그 코드들이 로드될 수 있다

 


2) Runtime
코드(실행 과정)에서 라이브러리를 오픈하고
심볼과 function을 로드하면서 실행시키는 방법으로 가능하며

아래에 있는 코드는 이에 대한 예시 코드이다

 

다이나믹 라이브러리가 필요한 대표적인 경우는
실행파일을 이미 가지고 있고
실행파일을 업데이트해 주기 위해서 다이나믹 라이브러리만 바꿔주고
실행파일의 재빌드 과정을 하지 않아도 되는 경우에 사용한다

#include <dlfcn.h>
#include <iostream>
int main()
{
	void * handle = dlopen("./libfoo.so", RTLD_LAZY);
	if(!handle)
	{
		std::cout << "No library" << std::endl;
		return 1;
	}

	void (*fooPtr)();
	fooPtr = (void(*)())dlsym(handle,"_Z3foov");
	const char* dlsym_error = dlerror();
	if(dlsym_error)
	{
		std::cout << "No symbol" << std::endl;
		return 1;
	}

	(*fooPtr)();
	dlclose(handle);
	return 0;

}

 



09. constexpr
런타임 중에 처리되는 연산을 컴파일 시에 처리하게 하는 문법이다
컴파일할 때, 미리 연산에 필요한 데이터들을 다 알고 있는 경우에만 사용 가능하다

#include <iostream>

class Square
{
public:
	constexpr Square(int l)
		: mL{ l }
	{

	}
	constexpr int area() const
	{
		return mL * mL;
	}
	constexpr int perimeter() const
	{
		return mL * 4;
	}

private:
	int mL;
};

int main()
{
	constexpr Square c{ 10 };
	int a = c.area();
	int b = c.perimeter();
	// 함수들이 호출되지 않고 바로 결과값이 도출
}

 


 

10. Attributes
# nodiscard

함수의 반환 값을 강제하는 역할을 한다

#include <iostream>

[[nodiscard]]
int fn()
{
	// do some work

	return 0;
}

int main()
{
	//fn();// 빨간줄 생김
	int a = fn();
}


# deprecated

작업을 하다가 함수를 바로 제거하는 것은 위험하기 때문에

삭제가 된 함수를 사용하면, 오류가 발생한다

#include <iostream>

[[deprecated("fn() is deprecatd")]]
int fn()
{
	// do some work

	return 0;
}

int main()
{
	fn();
}

 

# fallthrough

switch문에서 case에 반드시 break를 작성해야 하고

만약 break를 작성하지 않는다면, 오류로 추적을 한다

하지만 의도적으로 fallthrough를 하고 오류 추적이 불필요하다면

해당 attribute를 사용하면 된다

#include <iostream>

int main()
{
	int a = 1;

	switch (a)
	{
	case 1:
		std::cout << "1" << std::endl;
		break;
	case 2:
		std::cout << "1" << std::endl;
		[[fallthrough]];
	case 3:
		std::cout << "1" << std::endl;
		break;
	default:
		std::cout << "default" << std::endl;
		break;
	}
}

 

# maybe_unused

변수나 함수의 리턴 값이나 매개변수가 사용되지 않더라도 Warning이 발생하지 않도록 한다

[[maybe_unused]] int a = 10;
// x 변수가 사용되지 않아도 컴파일러 경고를 방지합니다.

[[maybe_unused]] void unusedFunction(int param) 
{
	// param 매개 변수가 사용되지 않아도 컴파일러 경고를 방지합니다.
}

 



11. Unit Test
유닛테스트는 구현된 부분을 테스트하며

버그를 수정하여 로직의 완성도를 높이는 것이다

 

유닛테스트의 장점은
초기 단계에서 버그를 잡을 수 있고
샘플 코드의 역할을 한다
또한, 유지 보수를 쉽게 만들어준다

C++에서 Unit Test를 하기 위해서는
Google Test를 이용하는 방법이 있다
이는 빌드해서 바이너리를 실행해야 테스트가 가능하다는 복잡함이 있다

 


 

12. Static code analysis
Static code analysis를 이용하면
빌드나 실행을 할 때 오류나 경고와 관련된 테스트 및 분석은 당연히 가능하고
컴파일 과정 없이 코드에 문제가 있는지도 확인이 가능하다
무료 Static code analysis 중에는 Cppcheck가 있다

 



13. Code Formetter

작성한 코드들을 특정한 코드 스타일로 변경해 줄 때 사용한다

IDE에서는 우리의 스타일 대로 작성하더라도
협업을 하는 경우에는 스탠더드 한 형태로 바꿔주는 코드 포매터를 이용한다
또한, 회사에서는 지정한 형태의 코드 포매터를 이용한다
커밋을 할 때 자동으로 코드 포매터가 적용되게 하려면 git hook을 이용하면 된다

저작자표시 비영리 변경금지 (새창열림)

'C++ > [노코프] C++' 카테고리의 다른 글

[C++ NOTE] Smart Pointer  (0) 2024.03.29
[C++ NOTE] Inheritance  (0) 2024.03.28
[C++ NOTE] OOP  (0) 2024.03.27
[C++ NOTE] Resource Move  (0) 2024.03.26
[C++ NOTE] Memory Structure  (0) 2024.03.24
'C++/[노코프] C++' 카테고리의 다른 글
  • [C++ NOTE] Inheritance
  • [C++ NOTE] OOP
  • [C++ NOTE] Resource Move
  • [C++ NOTE] Memory Structure
묻공러
묻공러
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.