매니지드 언어 사용자(C/C++)가 C# 입문하려는 데 조언해주시면 감사하겠습니다.

안녕하세요. 먼저 글을 읽어주셔서 감사합니다.

저는 주로 C/C++을 사용하고 Java나 C#는 간단한 공부로 사용해본 적이 있습니다.
최근에는 libclang을 이용해서 C++ 헤더 파일을 파싱하는 기능을 구현하고 있는데 누겟에 ClangSharp라는 닷넷 패키지가 있어서 C#으로 구현하고 있습니다.
C++로 구현하려면 llvm을 컴파일하고 번들화해서 프로젝트에 넣어야 하는데 그렇게 하면 프로젝트 크기가 너무 커져서요. 해야 하는 작업도 많구요 ㅠㅠ…
아무튼 각설하고 C#을 사용하면서 궁금한 게 몇가지가 있습니다.

1. C# api의 내부 동작은 개발자가 어떻게 확인해야 할까요?

C#은 MSDN의 문서가 잘 되어 있어서 API를 습득하는데는 크게 어려움이 없었지만 문제는 내부 동작에 대한 이해입니다.

다음은 MSDN에 List의 성능 고려 사항에 관련한 설명을 가져왔습니다.

둘 다 유사한 기능을 가진 클래스를 ArrayList사용할 List지 여부를 결정할 때 클래스는 List 대부분의 경우 더 나은 성능을 발휘하며 형식이 안전합니다.

왜 더 나은 성능이 나오는지에 대한 설명은 없고 개발자는 그저 믿고 사용해야 하죠.
그런데 저는 제가 이해하지 못하는 API를 사용하는 것 만큼 꺼려지는게 없더라구요.

혹시 C#도 cppreference처럼 컨테이너의 api가 어떻게 동작하는지 자세히 설명해 주는 웹사이트가 있을까요?

2. 매니지드 언어 입문하면서 바꿔야 하는 마인드는 어떤게 있을까요?

C/C++과 C#은 다른 언어니까 C/C++처럼 사용하면 안된다라는 생각이 막연하게 들긴하지만 어떤 마인드를 가지고 C#을 사용해야 하는 건지 궁금합니다.
요즘은 chatcpt로 C++ 코드를 작성해서 같은 C# 코드로 포팅해달라고 하는데 "이게 맞는건가? 내가 C#을 언매니지드 언어처럼 쓰려고 하는 게 아닌가?"하는 스스로에게 의문이 생기더라구요.

3. 기타 조언을 부탁드립니다.

C++의 std::string과 C#의 string의 차이가 생각보다 엄청 커서 헤매버렸는데요, 매번 api를 사용할 때 마다 이렇게 헤매야 하는 건지, 솔직히 말해서 좌절감이 느껴집니다;;
뭔가 조언을 주시면 정말 감사하겠습니다.

5개의 좋아요

음… 일단 다른거는 모르겠지만 2번 항목에 대해서는 참고할만한 글이 있어서
또 한번 성지글을 부활시켜봅니당…ㅋㅋㅋ

2개의 좋아요

동작을 자세하게 설명하기 보다는 코드로 직접 보시는 게 빠를 것 같습니다.

코드 확인이 어려우시다면 ChatGPT에게 물어보시는 것도 방법일 것입니다.

Reference Source (microsoft.com)
Source Browser (dot.net)

또한 C#을 하시면서 C++과 조금 달라야할 적은 객체지향적인 부분이라고 생각합니다.
물론 C#이 객체지향이기만 한 언어는 아니고 객체지향을 지원하는 언어이기 때문에 함수형의 형태를 섞어써도 됩니다. 대표적으로 LINQ가 있지요.

간단히 말하면 CPP의 Class 다중 상속 같은 개념없이 하나의 클래스 상속 계통을 만들어가시면서 기능을 캡슐화 하시면 될 것 같습니다.

또한 포인터의 기능을 적극 이용하시면서 하셨던 방식보다는 간단한 클래스의 참조형식에 포커스를 두시면 좋겠습니다.

마지막으로, 언메니지드 언어를 하시던 분들이 메니지드 언어로 넘어오시면서 가장 많이 껄끄러워하시는게 Garbage Collector의 존재라고 생각합니다.
GC를 못믿기 때문에 수동으로 가비지를 제거하겠다는 GC.Collect()의 빈번한 사용보단, GC를 보다 정확하게 파악하시고 GC에게 맡기는 메모리 관리 형식을 선택하시면 좋을 것 같습니다.

3개의 좋아요

effective c# 이책을 한번 읽어보시길 추천 드립니다.
API 내부동작은 ;;그걸 파시면 끝이 없고
“그저 믿고 사용한다” 이 개념이 아직 낯설지만 하시다보면
Gc가 알아서 하겠지 하시면 되요 너무 디테일하게 하시면 진도도 안나가고
그냥 프로젝트 몇번 소화하면서 애자일하게 나가시길 추천 드립니다.
언매니지드하게 쓴다는 개념이 아마도 byte나 shift 연산 포인터 같은것에 매몰되서
그 습관을 못버리시는것이 아닐까 하는데
그냥 수동 운전 하다가 자동운전 하는 개념으로 기존 class에 매몰된 사고를
intferface으로 관점을 바꾸는 개념이 좀 필요하다고 생각합니다.
자동 운전하는데 기어 변속 어떻게 되는지 관심 없잖아요 ㅎ
개인적으로 c#은 c++ 에서 +가 네개 붙어서 c# 이라고 생각할정도로
많이 다르고 개념이 틀리다고봅니다.
그리고 c# 에서 가장 피하고 변태적으로 싫어하는것이 관리 안되는 언매니지드 오브젝트긴 하죠

5개의 좋아요

그리고 질문제목이

매니지드 언어 사용자 (C/C++) 라고하셨는데 매니지드 언어 사용자(C/C++) 라고 하셔야 맞지 않을까요? ㅎㅎ

4개의 좋아요

바꿨습니다. 감사합니다 :slight_smile:

3개의 좋아요

조언 감사합니다. 첨부해주신 링크들이 많은 도움이 될 거 같아요. :slight_smile:

3개의 좋아요

원하시는 모든 정보가 다 있을지는 확실하지 않지만, 아래의 책들이 닷넷 프레임워크에 대한 상세한 동작이나 아키텍처를 잘 설명하고 있으니, 네이티브 언어를 사용하시는 분들의 궁금증 해소에 도움이 될 것 같아 목록을 추가합니다.

그리고 각 질문에 대한 저의 의견도 첨언해봅니다. :smiley:

  1. 내부 동작 확인은 https://referencesource.microsoft.com/ 또는 닷넷 어셈블리 디컴파일러를 이용해서 보는 것이 완전무결한 이해에 도움이 되실겁니다.

  2. 가비지 컬렉터를 너무 신뢰해서도, 너무 신뢰하지 못해서도 안된다는 생각입니다. 너무 신뢰한다면, 가비지 컬렉터가 해야 할 일이 늘어나 애플리케이션의 성능을 깎는 부작용을, 너무 신뢰하지 않는다면 애플리케이션 유지보수를 고민하느라 생산성 저하라는 부작용이 생길 수 있다고 생각합니다.

  3. ChatGPT 이야기를 하셨는데, std::string에서 자주 쓰던 함수를 C#에서는 어떻게 쓰는게 좋은지를 묻는 것처럼 차이점을 물어보면서 학습을 하시고, 그것을 체득한다면 쉽게 새로운 프로그래밍 언어를 정복하실 수 있지 않을까 생각합니다. 그리고 C#도 C++처럼 언어 스펙이 계속 발전하고 있긴 합니다만, 몇 가지 키 포인트 (LINQ, 제네릭, TPL)만 확인하고 사용하더라도 어려움이 거의 없을 것이므로 버전이 올라가는 것에 대해 너무 신경쓰지 않으셔도 된다고 생각합니다.

4개의 좋아요

그리고 생각난 김에, ChatGPT (GPT-3.5)한테 질문을 던져보니 이렇게 답해주네요. :laughing:

Q: C++의 std::string으로 문자열을 관리하는 것과 C#의 System.String으로 문자열을 관리하는 것은 어떻게 메모리 관리 관점에서 다른 것인지 알 수 있을까?

A: C++의 std::string과 C#의 System.String은 둘 다 문자열을 관리하는 데 사용되는 클래스입니다. 그러나 두 언어 간에는 몇 가지 메모리 관리 관점에서 차이가 있습니다.

C++의 std::string은 동적으로 할당된 메모리에 문자열 데이터를 저장합니다. 이는 C++의 표준 라이브러리에서 newdelete 연산자를 사용하여 할당 및 해제할 수 있습니다. 그러나 개발자는 명시적으로 메모리를 해제해야하며, 이를 잊어 버리거나 실수로 메모리를 해제하지 않을 경우 메모리 누수와 같은 문제가 발생할 수 있습니다.

반면 C#의 System.String은 .NET Framework의 관리 코드에 의해 메모리가 관리됩니다. .NET Framework는 자동으로 메모리를 할당하고 해제하며, 개발자가 메모리를 직접 해제할 필요가 없습니다. 이러한 기능은 "가비지 수집"이라는 프로세스를 통해 이루어집니다. 이는 자동으로 참조되지 않는 메모리를 정리하고 재사용 가능한 메모리를 최적화하여 시스템 성능을 향상시킵니다.

따라서 C++의 std::string은 개발자가 직접 메모리를 관리해야하므로 더 많은 작업이 필요합니다. 그러나 이를 통해 개발자는 더 높은 메모리 제어 수준과 더 높은 성능을 얻을 수 있습니다. 반면 C#의 System.String은 메모리 관리를 자동화하여 개발자가 더 적은 코드를 작성하고 더 안정적인 코드를 작성할 수 있도록합니다.

Q: C#에서 문자열 데이터를 극단적으로 매우 많이 사용한다면 어떤 성능 상의 부작용이 있을까?

A: C#에서 문자열 데이터를 극단적으로 많이 사용하는 경우에는 다음과 같은 성능 상의 부작용이 발생할 수 있습니다.

  • 메모리 사용량 증가: 문자열 데이터는 일반적으로 매우 큰 메모리 공간을 차지합니다. 따라서 많은 양의 문자열 데이터가 사용되는 경우에는 시스템의 메모리 사용량이 증가하게 됩니다. 이는 시스템의 성능에 영향을 미칠 수 있습니다.

  • GC 부하: C#의 가비지 수집기(Garbage Collector)는 사용되지 않는 객체를 정리하고 메모리를 회수하기 위해 주기적으로 실행됩니다. 하지만 많은 양의 문자열 데이터를 사용할 경우, 가비지 수집기의 작업량이 증가하게 되어 시스템 성능에 부정적인 영향을 미칠 수 있습니다.

  • 문자열 연산 성능 저하: C#에서 문자열은 불변(immutable)합니다. 이는 문자열 데이터를 수정할 때마다 새로운 문자열 객체를 생성하므로 메모리 사용량이 더욱 증가할 수 있습니다. 또한 많은 양의 문자열 데이터를 다룰 경우 문자열 연산의 성능이 저하될 수 있습니다.

  • 캐시 미스(Cache Miss): 문자열 데이터가 메모리에 저장될 때 일부 문자열 데이터는 캐시(Cache)에 저장됩니다. 많은 양의 문자열 데이터를 사용할 경우, 캐시에 저장되는 문자열 데이터의 수가 증가하게 되어 캐시 미스(Cache Miss)가 발생할 가능성이 높아집니다. 이는 성능 저하를 초래할 수 있습니다.

따라서 많은 양의 문자열 데이터를 다루는 경우에는 메모리 사용량 및 가비지 수집 작업 등의 부작용을 고려하여 적절한 성능 최적화를 수행해야 합니다. 예를 들어, 문자열 연산을 수행하기 전에 문자열을 StringBuilder 등의 가변(mutable) 데이터 구조로 변환하여 메모리 사용량을 최소화하고, 문자열 캐시를 사용하여 캐시 미스를 최소화하는 등의 방법이 있습니다.

이런 식으로 선문답을 해보신다면 막연한 두려움을 해소하는데 큰 도움이 되실거라고 생각합니다 ㅎㅎ

3개의 좋아요

Literal string과 String InternPool에 관한 내용은 언급해주지 않는군요. ㅎㅎ

캐시가 혹시 인턴풀을 언급하는 걸까…ㅋㅋ

4개의 좋아요

ChatGPT가 시간 안에 답을 내야 하는 방식으로 동작하다보니 디테일한건 의도적으로 생략할겁니다. ㅎㅎ

3개의 좋아요

상세한 답변 감사합니다 :slight_smile:

3개의 좋아요