C#을 다시 쓸 일이 생겼다. 주력으로 계속 안 쓰니깐 까먹게 된다. 그래서 다시 봤던 책을 보려고 했는데, 이런 생각이 들었다.
C# in Depth처럼 버전별 기능 정리를 하면 어떨까?
그래서 github에 csharp-features 프로젝트를 만들었다. 2.0에서 4.0까지 정리. unit test를 사용해서 피처를 확인했다. vs unit test 괜찮네. mock이 없는 거 빼고는 마음에 든다. 이것 좀 기본으로 넣어주지.
lua를 배울 때 project euler를 풀었는데, 이 방법도 괜찮다. 하지만 script 언어로 먼저 문제를 풀어봐서 그런지, C#으로는 풀 맛이 안 생기더라. 나중에 ruby를 배울 때, 다시 풀어볼 생각이다.

템플릿 만으로 이만큼 분량을 뽑아낼 수 있구나. 자세한 설명으로 템플릿 내공을 쌓는데 그만이다.
문장이 어렵다. 뭐 별수 있나. 여러 번 읽어야지. 내공이 부족한 탓도 있겠지만, 문장이 어려운 건 사실. 예제 코드가 많아 다행이야. 예제 코드 덕에 이해한 내용이 많았다.
거의 모든 표준 라이브러리에서 non-intrusive 구현 방법을 선택하기 때문에 조금 낯설 뿐 쉬운 방법이다.
글 주소는 http://www.viva64.com/en/l/
64비트 포팅 – 32비트 포인터들이여 안녕에서 소개한 20 issues of porting C++ code on the 64-bit platform보다 더 자세하게 설명한다.
설명도 자세하고 좋아 도움을 많이 받았다. 똑바로 일하라 (Rework)에서 다른 사람을 가르치는 걸 좋은 마케팅 방법으로 소개한다. 정말 그런 것 같다. 보고 있자니 PVS-Studio가 좋아져.
64bit 마이크로프로세서 아키텍처로는 IA64와 Intel 64가 유명. 당연히 서로 호환은 안 되고 담쌓고 지냄.
x86-64, AA-64, Hammer Architecture, AMD64, Yamhill Technology, EM64T, IA-32e, Intel 64, x64. 이거 다 같은 의미. 뭐 조금씩 다르거나 이렇게 된 역사나 이유가 있겠지만, 관심 없다. 귀찮아.
x86-64 아키텍처 주요 장점. x86 하위 호환성도 갖췄어요~
오예~ Win64에서는 호출규약(calling convention)이 하나밖에 없다. Win32에서는 많았지. __stdcall, __cdecl, __fastcal, ... 하지만 이거 때문에 32bit, 64bit 코드를 못 섞어 쓴다.

C#은 다른 언어와 비교했을 때, 발전 속도가 눈에 띄게 빠르다. 뭐 정신없을 정도. 언제 나올지 모를 C++0x를 기다리고 있자니 부러운 면도 있다. ((10진수가 아니라 16진수라는 소문이 있다.)) 아무튼 이렇게 빠르다 보니 언어가 강력해져 개발자로서 좋은 점도 많지만 반면에 새로운 버전이 나올 때마다 익혀야 하는 양을 생각하면 부담스럽기도 하다. 이러면 어떨까? 새로운 버전에 추가된 기능을 설명한다. 이전 버전 기준으로 짠 코드가 이렇게 바뀌는 걸 보여준다. 버전별로 추가된 기능을 설명하니 C# 발전 과정도 보이고 버전별 정리도 절로 된다. 계속 발전하는 과정을 보는거라 재미도 있다. 오예. 그 책이 바로 이 책이다.
Inside C#보다 먼저 읽었는데, Inside C# 이후에 읽으면 더 나을 뻔 했다. 내가 책 순서를 추천한다면 Inside C#을 먼저 읽고 이 책을 읽는 걸 추천하고 싶다. Inside C#만 읽으면 딱 C#1에 머무른 상태이다. 여기서 C# in depth로 차근차근 C#3까지 올라가면 재미도 있고 진짜 C#을 익히는 기분이 든다.
작년에 2판이 나왔다. 여기선 최신인 C#4까지 다루고 있다.

새로 배울 언어로 선택한 C#. 많은 부분이 다르지만 그래도 C++에서 많이 가져왔기 때문에 완전 기초 책은 보기 싫었다. 현업에서 C++을 사용하고 있는데, 변수를 어떻게 선언하는지나 if 문을 어떻게 쓰는지 이런 거 나오는 책을 보자니 좀 슬프다. ((비율 문제지 사실 안 나오는 책은 없다.)) 책을 찾아보던 중, 온라인에 공개된 책을 알게 됐다. 뭐 공개된 거니깐 한 번 슬쩍 보고 시원찮으면 다른 책을 찾아보기로 하고 다운로드 받아서 봤다. 아 좋네. 기초 책을 따로 구해서 안 봐도 되겠다. 이 책은 무료 기술 서적으로 msdn에서 다운로드 받을 수 있다.
괜히 inside가 붙은 게 아니었다. 깊이가 있다. 책 초반에 다른 C# 책에서 보기 힘든 응용 프로그램을 시작할 때, MSIL 코드가 실행되는 과정을 설명한다. 이거 처음부터 책을 기대하게 만드는구만. 좋은 초반 끝까지 유지한다. 깔 수 있으면 다 MSIL로 까서 설명하니 애매한 표현도 없고 딱 좋다. 설명이 좀 애매해도 MSIL이 다 설명을 해주니깐.
아무래도 좀 시간이 지난지라 예전 C#을 다루고 있다. ((흠.. generic이 안 나온걸로 봐서 1.1이 아닐까 추측만.. 책에서 내가 못 찾았는지 버전에 관한 얘기는 못 봤다.)) 이 부분은 웹으로 때우던지 책으로 때워야 할 듯.
Object* object = NULL;
if (object && object->IsValid())
{
// ...
}
C++에서 다음과 같은 코드가 있을 때, 죽을까 안 죽을까? 정답은 안 죽는다. Short-circuit evaluation 때문에 그런데, 이 용어가 생각이 안 나서 대학교 때 배운 Programming Language 책에서 용어를 찾았다. 그리고 기념으로다 포스팅.
Short-circuit evaluation을 간단히 설명하면 and, or 논리 연산에서 인자 하나만 보고 결과를 확실히 알 수 있을 때, 뒤에 나오는 인자를 확인하지 않고 바로 답을 내는 방법이다. and(&&) 연산일 때, 하나라도 false이면 무조건 답이 false이고 or(||) 연산일 땐, 하나라도 true이면 무조건 답이 true이다. C++뿐만 아니라 C#, Java도 Short-circuit evaluation을 지원한다. 지원하는 언어를 보려면 여기를 클릭.
STL에는 auto_ptr라는 스마트 포인터가 있지만 할당하면 소멸식 복사(destructive copy)로 자원에 대한 소유권을 넘겨주는 동작을 한다. STL 알고리즘은 값에 의한 복사가 기본 동작이라서 컨테이너에 못 넣는 스마트 포인터가 되겠다. 이게 이슈가 많이 돼서 이름도 있다. COAP(Container Of Auto_Ptr).
shared_ptr은 TR1(Technical Report 1)에서 추가된 스마트 포인터이다. 소유권을 넘겨주는 동작이 아니라 소유권을 나눠 가지는 스마트 포인터다. 우리가 흔히 스마트 포인터라 부르는 것처럼 동작한다. 자원 관리로는 아주 친근한 우리 친구 레퍼런스 카운터(reference counter)를 사용한다. 자원을 소유한 객체가 늘어나면 레퍼런스 카운터를 증가시키고 그 객체가 삭제되면 레퍼런스 카운터를 감소시켜서 결국 0이 되면 이 자원은 이제 사용하지 않으니깐 삭제한다.
class RVO
{
public:
RVO() { PrintLine("constructor"); }
RVO(const RVO& rhs) { PrintLine("copy constructor"); }
~RVO() { PrintLine("destructor"); }
RVO& operator=(const RVO& rhs)
{
PrintLine("assign operator");
return *this;
}
int dummy;
};
RVO MyMethod (int i)
{
RVO rvo;
rvo.dummy = i;
return rvo;
}
int main()
{
RVO rvo;
rvo = MyMethod(5);
return 0;
}
17번 줄에 MyMethod가 값으로 객체를 리턴(return by value)한다는 게 포인트다. 설명이고 자시고 출력 값부터 보자. 소스 코드는 MSDN 예제 코드를 조금 고쳤다.
class Base
{
public:
Base()
{
WriteLine("Base::Base()", typeid(*this).name());
f();
}
void f()
{
WriteLine("Base::f()", typeid(*this).name());
virt();
}
protected:
virtual void virt() { WriteLine("Base::virt()"); }
};
class Derived : public Base
{
public:
Derived()
{
WriteLine("Derived::Derived()", typeid(*this).name());
f();
}
protected:
virtual void virt() { WriteLine("Derived::virt()"); }
};
// main
Derived d;
Base::Base() - class Base Base::f() - class Base Base::virt() Derived::Derived() - class Derived Base::f() - class Derived Derived::virt()