항목

 내용 

 환경

 VS2010 

 언어

 C++, XML

 사용 라이브러리

 TinyXML2(https://github.com/leethomason/tinyxml2)


xml에 대한 설명은 https://ko.wikipedia.org/wiki/XML으로 대신한다.

Tiny XML-2는 간단하고, 작고, 효율적인 C++ XML parser로서 다른 프로그램에도 쉽게 통합될 수 있는 라이브러리다. DOM 방식을 이용하고, C++ 객체를 통해 데이터를 읽고 쓰고 저장할 수 있다. 아예 없는 문서를 객체를 통해 생성하는 것도 가능하다. 각각 한개의 CPP/H파일로 이루어져 단순히 기존 프로젝트에 추가하면 되기 때문에 사용이 간단하다.

이하는 사용 예시.


기존 프로젝트에 라이브러리 파일을 추가해 준다. Path 환경 변수로 설정하는 것도 가능하고, Project Settings에서 Include Path추가로도 가능하다.


헤더를 인클루드뿅


xml파일을 작성하는 예시이다. 에러 확인은 생략했다.


컴파일 후 실행시 프로젝트 폴더 내에 파일이 생긴다.


해당 파일의 내용은 코드로 작성한 것과 동일.


xml파일 속 데이터를 읽어오는 부분이다. 사실 Attribute의 이름은 몰라도 된다. 순차적으로 들고오는 연결리스트 식으로도 가능하기 때문.


출력 결과. 참고로 한자도 잘 적어지고 잘 읽어지는 것을 알 수 있다.


끝.

새벽동안 꽤나 고생했던 문제이다. 생각보다 해결은 쉽게 되었다.....

제목은 저렇게 거창하게 적혀있지만 실제론 게임에서 자주 사용되는 상황이기에 정리해 보았다.

여기서 잠깐 "나는 삼각비나 삼각함수를 모른다!" 하는 사람은 위키피디아, "삼각함수" 항목을 참고해도 좋다.


이 문제의 조건은 다음과 같다.


1. 점 A와 B가 존재한다. 예를 들어 A는 기준점, B는 가려하는 위치라고 생각해보자. (위치는 가변적이다.)

2. 점 A와 B를 직교선으로 이어 직각 삼각형을 만든다.

3-1. 각도 구하기인 경우 x, y, r(빗변, 피타고라스의 정리로 도출)이 모두 주어지는 상황이다.

3-2. x, y 좌표 구하기인 경우 각도와 r(빗변)이 주어지는 상황이다.


그림으로 나타내면 이런 느낌이라고 할 수 있다.



첫번째 문제인 x, y 좌표를 알 때 각도를 구해보도록 하자.

우선 위의 조건에서 라는 사실을 이미 알고 있다. 그럼 우리가 알아야 하는 값은 θ이다.

tanθ를 아는데 θ값을 구하려면 탄젠트의 역함수를 취하면 된다. 아크탄젠트라고도 한다.

수식으로 나타내면 이렇게 될 것이다. 

사실 수식이 다소 틀렸을 수도 있으나 애교로 봐주면 감사하겠다. 필자는 중학생 때 부터 쭉 수포자이며 수학을 공부한 적이 없다.


아무튼, 이제 우리는 아크탄젠트를 구해야 한다. 이는 math.h를 인클루드했을 시 몇개의 아크탄젠트 함수를 사용할 수 있다.

필자는 여기서 상당히 막혔다. 왜냐면 atan과 atan2의 차이를 몰랐기 때문이다. 애꿎은 삽질 덕분에 해가 뜨는 것을 보았다.(구라까는 거 아니다.)

생각해보면 당연하다. atan은 tanθ값을 넣는다. 나같은 수포자가 있을 것 같아 이해를 돕자면 다음의 두 경우를 생각해 보자.


case 1. x 거리가 -1이고 y 거리가 -1이면 tanθ 값은 1이 된다.

case 2. x 거리가 1이고 y 거리가 1이면 tanθ 값은 1이 된다.

∴ 두 경우 다 같은 각도를 갖는다(사실 좌표계를 배제하면 틀린 말은 아니다)


뭔가 이상하지 않은가!? 나는 이걸 눈치채는 데에 무려 장장 네시간이 걸렸다. 앞서 말했듯이 난 중학생 때 부터 쭉 수포자이다.

그래서 사분면의 위치, 파라미터의 음수값을 고려한 함수가 atan2이다. y 값과 x 값을 파라미터로 갖는 함수이다.

일단 우여곡절 끝에 우리는 atan2 함수의 반환값으로 라디안 값을 얻게 되었다. 이 값에 를 곱해주면 Degree값이 된다.

코드로 나타내면 이런 느낌일 것이다.


 m_fDegree = atan2f( (float)B.y - A.y, (float)B.x - A.x ) * 180 / 3.1415f;


자, 이렇게 우리는 각도를 얻었다!

이제 각도와 빗변을 알 때 x, y의 좌표를 구할 일이 남았다. 이 문제는 코사인과 사인만 있으면 바로 해결된다.

이건 그나마 정말 쉽다. x의 거리 부터 구해보도록 하자.



써놓고 굉장히 뿌듯했다. 딱 봐도 아 그렇군! 싶지 않은가?

특히 1차원적인 사고 및 하나를 알려주면 하나만 아는 필자에게는 굉장히 알아보기 쉬운 수식이다.

"약분해서 r이 떨어지면 x 거리만 남으니까 이렇게 x 거리를 구하겠군!"

같은 원리로 y의 거리를 구하는 것은 다음과 같다.



이러한 원리를 이용하여 앞에서 쓴 코드에 덧붙여보도록 하자.

각도는 자유로 정한다. 단, 파라미터로 들어가는 각도는 라디안임에 주의한다. 빗변의 길이는 10으로 예를 들자.

참고로 코사인과 사인 함수도 math.h에 포함되어 있으니 math.h를 인클루드했는 지 확인하기 바란다.


 m_iXDist = cos( m_fDegree ) * 10;

 m_iYDist = sin( m_fDegree ) * 10;


위의 코드로 얻은 거리 값에 현재 위치 값을 더하면 "특정 각도로 원하는 값 만큼 이동"이 된다!


이러한 각도 구하기 및 좌표 구하기를 적용하는 사례는 다양한 곳에 이용될 수 있다.

FPS 게임에서 마우스 이동으로 카메라를 회전시키는 것도 가능할 것이고, 원하는 각도로 총을 쏘는 것도 가능하다.

딱히 더 할 말이 없으므로 글을 마친다.

거두절미

예시는 벡터


std::vector<템플릿> 변수1;

for( std::vector<템플릿>::iterator 변수2 = 변수1.begin(); 변수2 != 변수1.end(); 변수2++ )

{

    *변수2.작업();

}


자세한 설명은 생략한다.

정말 자주 쓰는 디자인 패턴 중 하나인 싱글톤 패턴이다. 개인적으로 디자인 패턴 중에서는 제일 구현도 쉽고 활용도도 높지 않나 한다.

웬만한 객체지향 언어는 지원이 되므로 어떤 형식을 가지는지 이해하면 타 언어(Java 등)에서도 활용 가능하다.

 'static'으로 생성된 객체의 특징인 "프로그램이 실행 시 함께 할당되며(일반적으로), 프로그램 종료까지 메모리에서 해제되지 않는다"는 점을 이용하며,

단 하나의 객체만 만들고 실행 내내 해당 객체만 불러오는 특징이 있다. 그렇기 때문에 보통 프로그램 내에서는 매니저 클래스로 많이 사용된다.

 사용되는 예시는 다음과 같은 형식이다. 사용 시에는 Singleton::Instance->함수() 등 다양한 방법이 있다


class Singleton

{

public:

static Singleton* Instance()

{

if( !m_pInstance ) // 인스턴스 할당

m_pInstance = new Singleton;


return m_pInstance;

}


private:

Singleton()

{

//초기화

}


~Singleton()

{

// 인스턴스 자체는 new로 생성하기 때문에 자동 삭제된다

};


static Singleton* m_pInstance;

};


#include <iostream>


using namespace std;


class Root

{

public:


virtual void Function() = 0;

};


class Node1 : public Root

{

public:


void Function()

{

cout << "나는 자식 1이당~~~"  << endl;

}

};


class Node2 : public  Root

{

public:


void Function()

{

cout << "나는 자식 2이당~~~"  << endl;

}

};


int main()

{

int i;

Root * Test = 0;


cin >> i;


switch( i )

{

case 1:

Test = new Node1();

break;

case 2:

Test = new Node2();

break;

}


Test->Function();


delete Test;


return 0;

}

개요

 링크드 리스트나, 동적할당, 비트맵 등등을 한번에 마구잡이로 사용하다보면 가끔 자원 해제를 깜빡하여 미아가 되어 메모리 안을 떠도는 경우가 있습니다. 이를 해결해주는 것 중 Visual Leak Detector for Visual C++(이하 VLD)라는 유용한 라이브러리가 있습니다. 단순하게 프로젝트에 라이브러리를 추가해 주고, 헤더를 인클루드하면 디버깅 모드에서 메모리누수가 날 때 Output창에 출력해주는 것을 토대로 소스를 고쳐나가면 됩니다.



설치방법


공식사이트(https://vld.codeplex.com/) 에서 Downloads메뉴에 들어간 후, 원하는 버전을 다운받습니다.

파일을 다 다운받았다면 적당히 설치해 줍니다.



설치가 끝나면, VS에서 원하는 프로젝트를 열고, Project메뉴를 열고 Properties를 엽니다.



메뉴를 열고, VC++ Directories를 클릭합니다.



Include Directories에 VLD의 include폴더를 추가합니다.



Library Directories에 VLD의 lib폴더에서, 자신의 컴퓨터에 맞는 폴더를 선택하여 추가합니다.



사용하기


소스의 #include 부분의 최하단에 vld.h를 인클루드합니다.



디버그를 하면 누수가 생길 때 마다 위와 같이 Output 창에 누수 위치와 상세 정보가 출력됩니다.



누수가 없으면 이렇게 출력됩니다.

이 엄청난 누수를 어떻게 해결할까 힘들었는데, 해결하고 아무 누수가 없다는 글을 보니 기분이 상쾌해지네요.:)



+.덧붙임


릴리즈 모드와 디버그 모드를 구분해 사용하려면, VLD를 인클루드해주는 부분을 이렇게 수정합니다.

리눅스 : 컴파일 시 gcc -o OOO ./OOO.c -l[라이브러리 이름]

윈도우 : 소스 상단에 전처리 언어 #pragma comment(lib,"라이브러리 이름")

사용 절차

1. time 등의 함수를 사용하기 위해 time.h를 인클루드한다.

2. time_t 변수를 생성한다.(stTempTime으로 가정) 문자열을 저장할 변수를 생성한다.(cBuffer로 가정)

3. time( &stTempTime );

-> 현재의 시간을 저장하는 함수

4. strftime( cBuffer, 길이, "포맷", localtime( &stTempTime ) );

-> cBuffer에 해당 길이, 포맷에 맞게 변환하여 저장한다.

-> 포맷은 printf와 똑같은 방식이다. 사용예 : "%Y-%m-%d" -> "2013-08-04"

- %Y : 년도

- %m : 월

- %d : 일

- %H : 시

- %M : 분

- %S : 초

5. 문자열 출력


사용예시

time( &stTempTime );

strftime( m_message.m_time, 26, "%Y-%m-%d %H:%M:%S", localtime( &stTempTime ) );

printf 를 이용한 Debugging Tip

다들 프로젝트 하면서 디버그 한다고 난리 브루스 리 일텐데.. gdb같은 디버거 사용하지 않으면 printf 로 콕콕 찍어가면서 하고 계시겠죠.
파일이 분할이 많아지고 어느곳에서 나오는 메세지인지 정확히 알 수 있는 방법이 있습니다.

만약 아래의 소스를 test.c 에서 test_fuc라는 함수안 12번째 라인에 삽입했다고 하면,

printf("%s, %s, %d ERROR!!\n", __FILE__, __func__, __LINE__);        

위 printf문은 단순한 에러 처리에 진입했을때 나오는 나오는건데 분기가 많아서 어느 에러 문인지 정확히 찝어내기 위해서 사용했습니다.
사용된 인자들을 살펴보면 아래와 같습니다.

  • __FILE__ 파일명
  • __func__ 해당 코드가 속한 함수명. 소문자로 적어야 합니다.
  • __LINE__ 해당 코드의 줄 번호

위의 코드는 다음과 같이 출력 됩니다.

test.c, %test_func, 12 ERROR!!

그리고 저 코드들은 #ifdef DEBUG 과 #endif 안에 넣고 컴파일 할 때 -DDEBUG 라고 옵션을 줬을 때만 사용하게 하면 좀 더 편할 수 도 있겠지용.


저희 과정 선배님이 올려주셔서 퍼온 자료인데 원래 누가 쓰신건지 모르겠음 ^^;;;

strcmp는 사전상 위치를 비교하여 인자1이 인자2보다 앞에 있으면 -1을, 뒤에 있으면 1을, 같으면 0을 반환하는 함수이다.


strcmp로는 영문만 비교해보았는데, 한글을 비교할 일이 생겨서 어떻게 할지 고민하다가,

"우리는 완성형을 쓰는데, 어딘가에 ASCII코드처럼 순차적으로 저장되어 있지 않을까?"

해서 strcmp로 테스트 해 보았다.


걱정과 달리 아주 잘 되었다! 심지어 받침 비교도 잘 되었다.( 닭, 닳 같은... )

참 쉽게 해결한 것 같다. 또 필요할 때가 있을 지 몰라 써둔다.ㅎㅎ


예시 코드


#include< stdio.h >

int main()
{
    char m_string1[10];
    char m_string2[10];

    int m_cmp;

    while( 1 )
    {
        gets( m_string1 );
        gets( m_string2 );

        m_cmp = strcmp( m_string1, m_string2 );

        if( m_cmp == 1 )
        {
            puts( m_string2 );
        }
        else if( m_cmp == 0 )
        {
            printf( "위치가 같음\n" );
        }
        else
        {
            puts( m_string1 );
        }
    }
   return 0;
}


+ Recent posts