동적 링크 라이브러리 묵시적 사용 [Windows System Programming]

다루는 내용

라이브러리는 정적 라이브러리와 동적 라이브러리가 있습니다.

정적 라이브러리는 사용하는 라이브러리를 사용하는 프로그램 이진 파일에 포함하는 라이브러리입니다.

동적 라이브러리는 사용하는 프로그램의 이진 파일에는 어떤 라이브러리를 링크할 것인지 정보를 갖고 있고 런타임 시에 라이브러리를 링크하여 사용합니다.

C언어와 C++언어에서 컴파일 결과 파일이 obj인 파일들이 정적 라이브러리라고 할 수 있습니다.

Windows System에서는 동적 링크 라이브러리인 DLL을 작성하는 매커니즘을 제공하는데 이를 살펴보기로 할게요.

여기에서는 동적 링크 라이브러리를 묵시적(암시적) 으로 사용하는 방법을 알아볼게요.

1. DLL 소스 코드
2. 동적 링크 라이브러리 묵시적 사용1
3. DLL 소스 코드 + DLL 헤더
4. 동적 링크 라이브러리 묵시적 사용2
5. DLL에서 클래스 정의
6. 동적 링크 라이브러리 묵시적으로 클래스 사용

1. DLL 소스 코드

프로젝트 유형은 동적 링크 라이브러리로 제작합니다.(DemoLib 이름으로 만들게요.)

동적 링크 라이브러리에서 외부에서 사용할 수 있는 함수를 만들 때는 다음과 같은 표현을 사용합니다.

extern “C” __declspec(dllexport) 표현을 함수 정의문 앞에 나타냅니다.

extern “C” 의미는 함수 부호화(코드화)를 수행하지 말라는 의미입니다.

C++언어에서는 함수 중복 정의를 제공하며 컴파일 단계에서 함수 부호화를 통해 유일한 함수 이름으로 결정합니다. 이는 개발자가 정한 이름과 다른 함수 이름으로 결정함을 의미합니다.

extern “C”를 명시함으로써 개발자가 정한 이름을 함수 이름으로 사용하게 하는 것입니다.

__declspec() 은 이 부분을 외부에서 사용할 수 있게 제공할 것인지 외부에 있는 것을 사용할 것인지를 선언하는 부분입니다.

__declspec(dllexport) 표현은 외부에서 사용할 수 있게 제공하겠다는 의미입니다.

사용하는 곳에서는 __declspec(dllimport)를 표현하여 사용할 것을 선언합니다.

extern "C" __declspec(dllexport) int Add(int a, int b)
{
	return a + b;
}
extern "C" __declspec(dllexport) int Sub(int a, int b)
{
	return a - b;
}

2. 동적 링크 라이브러리 묵시적 사용1

콘솔 응용 프로그램을 작성합니다.

dll을 사용하는 프로그램을 제작하기 위해서는 lib 파일을 참조 추가하여야 합니다.

이 때 사용하는 매크로 구문이 #pragma comment(lib,”라이브러리 파일명”) 입니다.

라이브러리에 있는 함수를 사용하기 위해서는 extern “C” __declspec(dllimport) 표현이 함수 선언문 앞에 있어야 합니다.

#include <stdio.h>
#pragma comment(lib,"../x64/Debug/DemoLib.lib")
extern "C" __declspec(dllimport) int Add(int a, int b);
extern "C" __declspec(dllimport) int Sub(int a, int b);
int main()
{
	printf("%d\n", Add(2, 3));
	printf("%d\n", Sub(2, 3));
	return 0;
}

실제 동작하기 위해서는 dll 파일이 경로에 있어야 합니다.

3. DLL 소스 코드 + DLL 헤더

동적 링크 라이브러리를 만드는 개발자는 사용하는 개발자를 위해 헤더 파일을 같이 정의해 주면 좋습니다.

DemoLib.h

ifdef 매크로를 이용하여 정의할 것 같지 않은 상수명을 정의했을 때를 라이브러리 내부 용도로 그렇지 않았을 때 사용하는 곳에 필요한 코드를 표현하게 정의합니다.

#pragma once

#ifdef DIFWEFJSDFUEDIEDCIEMC438567CDIECMCUE3756CIEJ437567CIEJ
#define MY_DLL __declspec(dllexport)
#else
#define MY_DLL __declspec(dllimport)
#endif

extern "C" MY_DLL int Add(int a, int b);
extern "C" MY_DLL int Sub(int a, int b);

DemoLib.cpp

라이브러리 소스 코드의 헤더 파일 포함문 바로 앞에 요상한( 정의할 것 같지 않은 상수명)을 정의합니다.

#define DIFWEFJSDFUEDIEDCIEMC438567CDIECMCUE3756CIEJ437567CIEJ
#include "DemoLib.h"

extern "C" MY_DLL int Add(int a, int b)
{
	return a + b;
}
extern "C" MY_DLL int Sub(int a, int b)
{
	return a - b;
}

4. 동적 링크 라이브러리 묵시적 사용2

라이브러리에서 제공하는 헤더 파일을 포함합니다.

물론 라이브러리를 참조하는 매크로 구문도 표현합니다.

#include <stdio.h>
#include "../DemoLib/DemoLib.h"
#pragma comment(lib,"../x64/Debug/DemoLib.lib")

int main()
{
	printf("%d\n", Add(2, 3));
	printf("%d\n", Sub(2, 3));
	return 0;
}

5. DLL에서 클래스 정의

DLL에 정의한 클래스를 외부에서 사용하기 원한다면 class와 클래스 명 사이에 __declspec(dllexport) 표현을 추가합니다.

사용하는 곳에서는 __declspec(dllimport)로 명시합니다.

사용하는 개발자가 편리하게 헤더 파일을 다음처럼 정의합니다.

Stu.h

#pragma once
#ifdef DXIEGVFUENJCYEHCVYEBCH39575667DCUENCUECYENCHE
#define STU_DLL	__declspec(dllexport)
#else
#define STU_DLL	__declspec(dllimport)
#endif
#include <string>
using std::string;
class STU_DLL Stu
{
	string name;
	int num;
public:
	Stu(string name, int num);
	string GetName();
	int GetNum();
};

Stu.cpp

소스 코드는 특별한 사항이 없습니다.

#define DXIEGVFUENJCYEHCVYEBCH39575667DCUENCUECYENCHE
#include "Stu.h"
Stu::Stu(string name, int num)
{
	this->name = name;
	this->num = num;
}
string Stu::GetName()
{
	return name;
}
int Stu::GetNum()
{
	return num;
}

6. 동적 링크 라이브러리 묵시적으로 클래스 사용

동적 링크 라이브러리에 있는 클래스를 사용하는 것은 별 다른 것이 없습니다.

단지 라이브러리 헤더 파일을 포함하고 라이브러리를 참조를 할 뿐입니다.

#include "..\StuLib\Stu.h"
#pragma comment(lib,"StuLib.lib")
#include <iostream>
using std::cout;
using std::endl;
int main()
{
	Stu* stu = new Stu("공길동",3);
	cout << stu->GetName() << "," << stu->GetNum() << endl;

	return 0;
}