C++ 개발자를 위한 C# 에 대한 문서

회사에서 게임관리툴을 만들기 위해 C#을 애용하고 있다. 이유는 무엇보다도 생산성이 높으니까. MFC 같은 것으로 해도 되지만 MFC는 번거로운 면도 많을뿐더러 MS가 C#을 밀고 있기 때문이다.
그런데 C#을 하다보면 C++에서 나왔던 습관들이나 C++에서 쓰던 것들이 안 보여서 난처할 때가 가끔 있다. 예를 들면, memcpy()나 typedef 같은 것들 말이다.
2026년 수정 안내 원래 이 글에는 “C#에는 memcpy()나 typedef 같은 것들이 없다”고 적었는데, 정확하지 않았다. 둘 다 대응하는 기능이 C#에 있다. 이름과 형태가 다를 뿐이다. 바로잡고, C#이 이후 크게 바뀐 부분도 덧붙인다.
memcpy에 대응하는 것
용도에 따라 다르다.
배열을 그대로 복사할 때 — Array.Copy / Buffer.BlockCopy
int[] src = { 1, 2, 3, 4, 5 };
int[] dst = new int[5];
Array.Copy( src, dst, src.Length ); // 타입을 아는 배열 복사
Buffer.BlockCopy( src, 0, dst, 0, 20 ); // 바이트 단위 복사. memcpy에 가장 가깝다
포인터로 메모리를 직접 다뤄야 할 때 — Marshal.Copy / unsafe + Buffer.MemoryCopy
네이티브 코드와 데이터를 주고받거나 포인터 연산이 필요할 때는 unsafe 컨텍스트에서 진짜 C++ 스타일로 쓸 수도 있다. fixed로 고정하는 포인터의 타입은 배열의 원소 타입과 일치해야 한다 — int[]를 곧바로 byte*로 고정할 수는 없다.
int[] srcInt = { 1, 2, 3, 4, 5 };
int[] dstInt = new int[5];
unsafe
{
fixed ( int* pSrc = srcInt, pDst = dstInt ) // 배열 원소 타입(int)과 맞춘다
{
// Buffer.MemoryCopy는 void*를 받으므로 byte*로 바꿀 필요조차 없다.
Buffer.MemoryCopy( pSrc, pDst, dstInt.Length * sizeof( int ), srcInt.Length * sizeof( int ) );
}
}
네이티브 버퍼(IntPtr)와 관리되는 배열 사이라면 Marshal.Copy를 쓴다.
Marshal.Copy( nativeIntPtr, managedByteArray, 0, length );
typedef에 대응하는 것
타입 별칭 — using
using PlayerId = System.Int32;
using PlayerTable = System.Collections.Generic.Dictionary<int, PlayerInfo>;
C++의 typedef가 하던 일과 거의 동일하다. using 별칭은 지금도 파일 맨 위에 두는 지시문이라는 점은 그대로다. C# 12에서 바뀐 것은 위치가 아니라 별칭으로 지정할 수 있는 타입의 범위다 — 이전에는 이름 있는 타입만 별칭으로 지정할 수 있었지만, C# 12부터는 튜플·배열·포인터 같은 타입도 별칭으로 지정할 수 있게 되었다.
using Point = (int x, int y); // C# 12부터 가능 - 튜플 타입도 별칭 지정
함수 포인터에 대응하는 것 — delegate
C++에서 함수 포인터 타입을 typedef로 이름 붙이던 용도라면, C#에서는 delegate가 그 역할이다.
public delegate void PacketHandler( byte[] data );
PacketHandler handler = OnReceivePacket;
C#은 그 사이 많이 바뀌었다
원래 이 글에서 소개했던 참고 문서는 2007년, Visual Studio 2008 기준이었다. “달라진 게 없을 것”이라고 적었는데, 실제로는 그 뒤로 C#이 크게 바뀌었다.
- LINQ (C# 3.0, 2007) — 컬렉션을 질의문처럼 다룬다.
async/await(C# 5.0, 2012) — 비동기 코드를 동기 코드처럼 쓸 수 있게 됐다.dynamic(C# 4.0, 2010), 패턴 매칭 (C# 7~9), nullable 참조 타입 (C# 8.0), 레코드(C# 9.0) 등.
지금 C++ 개발자가 C#으로 넘어온다면, 당시 문서보다는 Microsoft Learn의 C# 문서를 참고하는 편이 훨씬 정확하고 최신이다. 원래 링크했던 MSDN 문서는 현재 접속되지 않는다.
댓글 남기기