Altruistic Programmer's Blog (KR)

이타주의 프로그래머의 블로그

Archive for the ‘프로그래밍’ Category

Programming in Lua 2E 야매요약본

without comments

[옛날 블로그 글입니다. 2007/06/15]
[여전히 일본어 잘하고 싶음 -_-;;]

 

programminginlua2e_summary-muscly

Programming in Lua 2E 를 읽고나서 대략 정리한 내용.

팀에 PT 하려고 정리한 거라서 coroutine이나 thread, 객체지향프로그래밍 등등은 생략했다.

1시간 반 시간 잡고 했는데 반도 설명 못한듯 -_-;;

 

일본어 잘하게 되면 일본 개발자들 대상으로 해봐야지 ㅎㅎ

Written by muscly

April 10th, 2010 at 6:04 pm

Posted in 프로그래밍

undname.exe

without comments

[옛날 블로그 글입니다. 2007/09/20]
[요새는 에러 메시지가 친절해져서 필요없을 수도..]

 

Visual Studio와 함께 설치되는 유틸 undname.

데코레이팅된 C++ 심볼의 이름을 언데코레이트 해주는 유틸리티.

 

[오늘의 문제]

Q. 분명히 제대로 lib 파일을 링크해주었는데, 왜 심볼을 찾을 수 없다는 링크에러가 나는 것일까?

 

[풀이 과정]

1. 링크에러 메시지를 살펴보니 다음의 심볼을 못찾고 있다.

?CreatePane@VSIDE@vsautomation@@YAPAUHVSOutputPane__@VSOutputPane@2@PAUHVSIDE__@12@PB_W@Z

 

2. lib 파일을 열어서 CreatePane으로 검색해보니 비슷한 심볼이 보인다. (아주 살짝 틀리다)

?CreatePane@VSIDE@vsautomation@@YAPAUHVSOutputPane__@VSOutputPane@2@PAUHVSIDE__@12@PBG@Z

 

3. 두 심볼을 undname 을 통해 원래의 모습을 확인해보니 차이가 명확하다.

아래는 실행 화면. 노란 부분이 각 심볼의 원래 모습.

 

 

C:\Documents and Settings\jp90637>undname ?CreatePane@VSIDE@vsautomation@@YAPAUH
VSOutputPane__@VSOutputPane@2@PAUHVSIDE__@12@PBG@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation 1981-2001. All rights reserved.

Undecoration of :- "?CreatePane@VSIDE@vsautomation@@YAPAUHVSOutputPane__@VSOutpu
tPane@2@PAUHVSIDE__@12@PBG@Z"
is :- "struct vsautomation::VSOutputPane::HVSOutputPane__ * __cdecl vsautomation
::VSIDE::CreatePane(struct vsautomation::VSIDE::HVSIDE__ *,unsigned short const
*)"


C:\Documents and Settings\jp90637>undname ?CreatePane@VSIDE@vsautomation@@YAPAUH
VSOutputPane__@VSOutputPane@2@PAUHVSIDE__@12@PB_W@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation 1981-2001. All rights reserved.

Undecoration of :- "?CreatePane@VSIDE@vsautomation@@YAPAUHVSOutputPane__@VSOutpu
tPane@2@PAUHVSIDE__@12@PB_W@Z"
is :- "struct vsautomation::VSOutputPane::HVSOutputPane__ * __cdecl vsautomation
::VSIDE::CreatePane(struct vsautomation::VSIDE::HVSIDE__ *,wchar_t const *)"

 

 

4. 보아하니 lib를 만들때는 'wchar_t를 unsigned short로 다루기' 옵션으로 빌드되었고,

사용하는 쪽은 'wchar_t를 내장타입으로 다루기' 옵션으로 빌드되었다. (굵은 부분 참조)

 

[오늘의 교훈]

undname으로 사소한 링크 문제를 해결하자.

VC 2003에서 Win32 static library를 만드니 wchar_t를 unsinged short으로 다루더라.

반면에 MFC App는 wchar_t를 내장 타입으로 다루더라.

Written by muscly

April 9th, 2010 at 8:57 pm

Posted in 프로그래밍

RTTI 관련 정보

with one comment

[옛날 블로그 글입니다. 2007/11/29]

 

사내 C++ 강좌를 준비하던 중에 RTTI 구현을 좀 파고 들어봤다.

정리하고 나니 사내 강좌용으로는 좀 어려울 것 같아서

그냥 여기에 정래해 둬야 겠다 -_-;;

 

-

typeid() 연산자의 내부 코드의 일부 발췌 (VS7.1)

 

 004283AE  mov         ecx,dword ptr [inptr]   // intptr이 객체의 주소
004283B1  mov         edx,dword ptr [ecx]  // vfptr의 값을 꺼낸다. 즉, vftable의 주소
004283B3  mov         eax,dword ptr [edx-4] // vftable 바로 앞의 4바이트를 읽는다. RTTI 정보 주소
004283B6  mov         dword ptr [pCompleteLocator],eax 
// RTTI 정보 주소 얻기 성공!!

 

결론은, vftable 바로 위에 RTTI 정보 (RTTI Complete Object Locator)의 주소가 보관된다.

 

-

RTTI 정보의 구조 (VS7.1) 

아래에서 Mac 은 클래스의 이름이다.

그리고 pTypeDescriptor ( RTTI Type Descriptor)가 바로 type_info 클래스가 된다.

결론은 RTTI 정보에서 12바이트 옵셋에 type_info 클래스의 주소가 보관된다.

 

-

이 정보를 토대로 나만의 type_id 연산자 만들기.

확인을 위한 것 뿐이므로 범용적이지는 않다. (포인터 타입 안됨 ㅎ )

 

 #include <typeinfo>

 

typedef unsigned int __w64  DWORD;

using namespace std;

 

class Computer {
 virtual void Func() {} };

 

class Mac : public Computer {};

 

template < class T > const type_info& my_typeid( T& obj )
{
 DWORD* vfptr = (DWORD*) &obj;
 DWORD* vftable = (DWORD*) *vfptr;
 DWORD* rtti_info = (DWORD*) *(vftable – 1);
 DWORD* type_descriptor = (DWORD*) *(rtti_info + 3);
 type_info* result = (type_info*) type_descriptor;
 return *result;
}

 

template < class T > const type_info& my_typeid( T* ptr )
{
 throw "Pointers NOT supported!!";
}


int _tmain(int argc, _TCHAR* argv[])
{
     Mac mac;
     Mac* pm = &mac;
     Computer* pc = &mac;

     cout << typeid( pm ).name() << "\n";
     cout << typeid( *pm ).name() << "\n";
     cout << typeid( pc ).name() << "\n";
     cout << typeid( *pc ).name() << "\n";

 

     cout << my_typeid( *pm ).name() << "\n";
     cout << my_typeid( *pc ).name() << "\n";

     return 0;
}

>> 결과

class Mac *
class Mac
class Computer *
class Mac
class Mac
class Mac
Press any key to continue

 

 

Written by muscly

April 4th, 2010 at 1:55 pm

Posted in 프로그래밍

가상함수 호출시 this 포인터의 조절

with one comment

[옛날 블로그 글입니다. 2007/11/29]

멤버함수 포인터를 조사하다가 생각치 못한 점을 발견했다.

가상함수를 호출할 때도 this 포인터를 적절히 조절해야 한다는 점이다.

그런데, MSVC는 도대체 어디서 this 포인터를 조절할까? 

 

 class Base1

{

 public:

    virtual void Func1();

    int base1;

};

 

class Base2

{

public:

    virtual void Func2();

     int base2;

}

 

class Derived : public Base1, public Base2

{

public:

    virtual void Func2()    {

         ++ derived;

    }

    int derived;

}

 

Derived d;

Base2* pb2 = &d;

pb2->Func2();

pb2와 &d 는 다른 값이니까, 마지막 줄에서 this 포인터를 전달할 때 pb2에서 8바이트를 빼서
넘겨줘야 한다고 생각했지만, 어디에도 그런 코드는 없었다.

조사해보니, 가상함수의 코드를 생성할 때 아예 this 포인터가 부모기준으로 넘겨오겠거니..

생각하고 어셈블리 코드를 만들어준다.

 

-

하지만 항상 그렇게 할 수 있는 건 아니다.

아래의 예라면 위의 수법이 통하지 않는다.

 

 class Base1

{

 public:

    virtual void Func();

    int base1;

};

 

class Base2

{

public:

    virtual void Func();

     int base2;

}

 

class Derived : public Base1, public Base2

{

public:

    virtual void Func()    {

         ++ derived;

    }

    int derived;

}

 

Derived d;

Base2* pb2 = &d;

pb2->Func();

Derived::Func() 를 Base1의 this를 기준으로 어셈블해주면
Base2를 통해서 호출할 때는 필히 this 포인터의 조절이 필요하다.

MSVC는 이런 경우 this포인터값을 필요한 만큼 조절해서 Derived::Func()를 호출하는

코드 청크를 만들고, 이 청크의 주소를 Derived::Base2::'vftable'에 넣어둔다.

 

  @ILT+2080(?Func@Derived@?9??main@@9@W7AEXXZ):
00419825  jmp         [thunk]:`main'::Derived::Func`adjustor{8}' (void) (420580h)

청크 코드를 보면 this포인터에서 8을 빼고 실제 함수를 호출한다.

[thunk]:`main'::Derived::Func`adjustor{8}' (void):
00420580  sub         ecx,8 
00420583  jmp         `main'::Derived::Func (419686h) 

Written by muscly

April 3rd, 2010 at 1:48 pm

Posted in 프로그래밍

사원수 Quaternions

with 2 comments

[옛날 블로그 글입니다. 2007/12/19]
 

출처 : Tricks of the 3D game programming gurus p.325

 

[사원수란?]

복소수(Complex Numbers)처럼 실수부와 허수부로 구성된 수.

허수부가 i, jk 세개다.

 

q = q0 + q1*i + q2*j + q3*k

q는 사원수 )

i^2 = j^2 = k^2 = i*j*k = -1 )

( q0, q1, q2, q3 은 실수 Real Numbers )

 

이렇게도 표현

q = q0 + qv, where qv = q1*i + q2*j + q3*k

 

[사원수의 켤레(Conjugate)]

켤레수는 이차방정식의 두 근을 부르는 이름 인 것 같다.

무리수(Irrational Numbers) 부분이 +/- 로 부호만 다르게 된다.

복소좌표라면 허수 부분(Imaginary part)이 +/-로 부호만 다르게 된다.

 

다음은 사원수와 그의 켤레수.

q = q0 + q1*i + q2*j + q3*k = q0 + qv

q* = q0 - q1*i - q2*j - q3*k = q0 - qv

 

다음은 켤레수의 곱. 실수부만의 제곱이 된다.

q * q* = … 중간 생략 = q0^2 + q1^2 + q2^2 + q3^2

 

[놈(Norm)]

놈이란 벡터 공간 안의 모든 벡터에 양수의 길이나 크기를 부여하는 함수를 말한다.

2차원 유클리드 공간(Euclidean space) R^2에서의 유클리드 놈(Euclidean norm)이 좋은 예.

왜, 2차원 데카르트 좌표계(Cartesian coordinate system)에 벡터를 매핑 시키고 그 길이를

재는 방식 말이다.

 

위에 말을 정리하려고 열심히 웹서핑을 했지만, 위키피디아가 제일 나은 듯.

http://en.wikipedia.org/wiki/Norm_%28mathematics%29

 

사원수의 놈은 4차원 유클리드 공간 R^4에서의 벡터의 길이를 재는 것처럼 할 수 있다.

( 실수부, i, j, k 를 4차원의 축에 매핑시킨다고 생각하면 될 듯.. )

 

다음은 사원수와 놈.

q = q0 + q1*i + q2*j + q3*k = q0 + qv

|q| = sqrt(q0^2 + q1^2 + q2^2 + q3^2)

       = sqrt( q * q* )  <- 이렇게 되는 이유는 위의 켤레수 참조

|q|^2 = (q0^2 + q1^2 + q2^2 + q3^2) = ( q * q* )

 

[켤레와 역원(Inverse)]

역원의 정의는 당근 이렇게. q-1 은 q 빼기 1 아님 -_-;;

q * q-1 = q-1 * q = 1

 

위 식의 양변에 켤레를 곱하면 재밌는 결과가 나온다.

q-1 * q = 1

=>  ( q-1 * q ) * q* = 1 * q*

=>  q-1 * ( q * q* ) = q*

=> q-1 * |q|^2 = q*   <– 위에 놈(?) 참조

=> q-1 = q* / |q|^2

 

그래서 q 가 단위 사원수(unit quaternion)가 되면 |q|^2 = 1 이 되어서

아래와 같은 식이 나온다.

q-1 = q*, where |q|^2 = 1

 

[사원수를 사용한 회전]

사원수를 사용하는 것이 회전 행렬을 사용하는 것 보다 빠르고,

짐볼락(Gimbal lock)이 없는 것으로 유명.

그리고 회전시의 보간에도 유용하다는데, 아직 여기까지는 공부가 부족 -_-;;

 

벡터 v1을 기준으로 θ만큼 회전하는 사원수를 만들고 싶다면 이렇게.

q = cos(θ/ 2 ) + sin(θ/ 2 ) * v1

 

이렇게 준비한 사원수를 가지고 벡터 v2를 회전시키려면 이렇게.

우선은 벡터를 사원수 형식으로 바꿔야 하는데, 실수부는 0으로 두면 된다.

v2 = <x,y,z> 라면 vq = <0,x,y,z> 처럼 말이다.

 

왼손 좌표계라면

시계방향 회전은, vres = q * vq * q*

반시계방향은 , vres = q* * vq * q

오른손 좌표계라면 위의 식을 반대로 써주면 된다.

 

오일러(Euler) 회전각을 알고 있는 경우라면,

각 축에 대한 회전 사원수를 만들어서 곱해주면 된다.

qfinal = qx * qy * qz <- qx, qy, qz의 순서는 바뀌어도 무관

 

[DirectX 와 사원수]

뭐 다양한 사원수 지원이 있겠지만, 위에서 해본 것을 DX로 구현해본다면.

x, y, z가 각 축의 회전각(라디안)이라고 가정한다면

사원수는 이렇게 구할 수 있다.

 

var quat = Quaternion.RotationYawPitchRoll( y, x, z )

( VS 2008에서 Managed DirectX를 쓴 경우이다. )

 

바로 사원수를 행렬로 바꿀 수도 있다.

var mat = Matrix.RotationQuaternion( quat );

 

그런데 Matrix.RotationYawPitchRoll()을 써도 같은 행렬이 나오는 듯 -_-;;

Written by muscly

April 2nd, 2010 at 1:39 pm

Posted in 프로그래밍