C#에서 에서 C++ dll 을 사용해보자.

김응기·2023년 12월 25일
0
post-thumbnail

우리 회사에서는 C#을 이용해 개발을 하지만, 최근까지도 Delphi나 MFC와 같은 고대유물을 사용하여 개발을 하였다.

Delphi 는 굉장히 잘만들어진 Tool이라고 생각한다.
저수준 레벨의 프로그래밍이 가능하며 C++ 과도 유사한 성능을 내주니 말이다.

하지만 개인적으로는 Pascal언어를 극혐한다.(중괄호 없이 begin end는... 정말...)
그리고 초기 셋팅시 수많은 component설치, delphi 라이센스 비용 및 유지보수 인력 구하기 등 이젠 역사속으로 놓아주어야 할 녀석으로 보인다.

그렇다면 MFC는 어떨까?
성능 자체는 너무나 좋은 녀석이지만 이 녀석을 가지고 UI를 만들다보면 고대에 활동하시던 선배 개발자님들을 존경하게 된다.
UI 한페이지 짜는데 3~4일이 걸리니 말이다...
버튼 같은 컨트롤을 커스텀 하려면 한숨부터 나온다.

그렇다면 대체제는 QT? 얘도 라이센스 비용...ㅠㅠ

그래서 우리 회사는 .NET 환경에서 winform이나 wpf로 개발을 한다.
MFC로 개발하다 WPF로 개발을 하면 천국을 맛보는 기분이다.
누군가는 XAML이 극혐이라고 하지만, 개인적으로 HTML,CSS환경보다 훨씬 유연하고 자유롭게 UI커스텀이 가능하다고 본다.
더군다나 Visual studio에 내장되어있는 Blend까지 있다면.. UI 개발로는 최강이지 않나 싶다.
하지만 이녀석의 문제는 C# 을 사용한다는 것이다.

C#은 내가 제일 좋아하는 언어이지만, 이놈의 가장 큰 문제는 성능(GC...)이다.
물론 단순한 어플리케이션을 만든다면 C#으로도 차고 넘치지만..
게임엔진이나 영상 처리 같은 딥한 연산이 필요하다면 현재로선 C++ 만한것이 없을것이다.
(반박시 님이 맞음)

자 그렇다면 C++ DLL을 사용하여 C#에서 호출하여 쓸수 있는 예시를 보자.

C++ DLL 만들기

자 일단 준비물은 Visual Studio 가 필요하다.
비주얼 스튜디오에서 새 프로젝트를 생성하고 해당 템플릿을 선택해준다.

Functions.cpp 그리고 Functions.h 파일을 만들어주었다.
단순한 For문을 돌리고 반복문이 도는 시간을 체크하는 로직을 작성 해주겠다.

Functions.cpp

#include "pch.h"
#include "Functions.h"
#include <chrono>
#include <ratio>

double ForTest(int length)
{
	auto start_time = std::chrono::high_resolution_clock::now();
	int j = 0;
	for (int i = 0; i < length; i++)
	{
		j++;
	}
	auto end_time = std::chrono::high_resolution_clock::now();
	std::chrono::duration<double, std::milli> elapsed_time = end_time - start_time;

	double elapsed_ms = elapsed_time.count();

	return elapsed_ms;
}

Functions.h

#pragma once
extern "C" __declspec(dllexport) double ForTest(int length);

자 여기서 중요한 포인트가 나온다.

extern "C" __declspec(dllexport) 뭔 외계어냐 이거?

일단 C++ 자체가 익숙하지 않은사람들은 이 키워드를 보고 멘붕이 올거다.
차근차근 하나씩 알아보자.

extern "C"
해당 함수의 이름 맹글링(name mangling)을 막고 C 스타일의 함수 호출 규약을 사용하도록 지정한다.

__declspec(dllexport)
Microsoft Visual C++ 컴파일러에서 사용되는 확장 키워드이다.
함수나 클래스를 DLL 로 내보내기 위해 사용된다.

결론

extern "C"를 쓰지 않으면 C++규칙대로 함수에 독자적인 심볼을 붙이기 때문에 export 해서 사용할때 호환이 되지 않는다. 그리고 __declspec(dllexport) 요 키워드는 dll로 export 하기 위해 사용된다.
대충 이유는 이렇고 그냥 외웁시다ㅎ

빌드

비주얼스튜디오 기준 Cntl + B 단축키로 프로젝트를 빌드해준다.
빌드를 해주면 요렇게 dll 파일이 만들어진다.

C# 프로젝트에서 함수 실행을 해보자.

일단 C# Console 프로그램 프로젝트를 만들어주자.

그리고 중요한거!
보통 .NET 프로그램은 프로젝트 폴더 내 bin 폴더에 빌드 된 실행파일들이 만들어진다.
debug, 혹은 release 인지 잘 확인 후 앞서 만들었던 dll을 잘 넣어주자.

Program.cs

using System.Runtime.InteropServices;

class Program
{

    [DllImport("TestDll2.dll")]
    public static extern double ForTest(int length);

    public static void Main(String[] args)
    {
        var cppResult = ForTest(100000000);
        Console.WriteLine("CPP 결과 : " + cppResult + "ms");

    }

System.Runtime.InteropServices 참조하여 dllImport를 해준다.

문득 C#과 C++ 의 속도 비교를 해보고 싶어졌다.
그래서 위 코드에 함수를 하나 더 추가해주자.

    public static double CSharpForTest(int length)
    {
        DateTime startTime = DateTime.Now; // 시작 시간 기록
        int j = 0;
        for (int i = 0; i < length; i++)
        {
            j++;
        }
        DateTime endTime = DateTime.Now; // 종료 시간 기록
    
        TimeSpan elapsedTime = endTime - startTime; // 경과 시간 계산
    
        double elapsedMilliseconds = elapsedTime.TotalMilliseconds; // 경과 시간을 밀리초로 얻음
    
        return elapsedMilliseconds;
    }

그리고 실행해보자.
결과는??

드라마틱 하게 차이나진 않지만 그래도 C++ 이 더 빠르네 ^^;

이번 포스팅에선 기본적인 함수 호출을 해봤지만, 다음 포스팅에선 WPF에서 사용하는 예시, 포인터를 리턴받아서 사용하는 방법등을 올려보겠다.

profile
앱등이인데 .NET 개발자이고.. 개발자인데 락스타를 꿈꾸는 사람!

0개의 댓글