오전 시간 전부와 오후 시간 조금을 갉아 먹은 코드.

퇴근하기전에 해결하지 못한 코드를 다음 날로 미루고 퇴근한 바로 그 다음날인 오늘, 다시 문제의 코드를 살펴보는데, 도무지 모르겠더라.. 여차저차 해서 문제가 발생하는 방향과 문제가 발생하지 않은 방향은 알게 되었는데.. 그 원인이 무엇인지는 여전히 모르겠더라..

Need는 3DS 파일을 로딩하여 화면상에 표시하는 어느 외국(DigiBen, digiben@gametutorials.com)인 잘만들어 공개해 놓은 소스 코드를 사용하려고 하는데.. 핵심적인 사용은 클래스 하나와 구조체 하나를 조합하여 사용하는 것이었다.

문제는 시험차원에서 만들어 놓은 코드는 잘작동을 하는데, 실제 프로젝트에 적용을 해보면 프로그램이 뻗어 버렸다. 여차저차해서 겨우 문제가 발생하는 경우와 발생하지 않는 경우를 알게되었는데..

문제가 발생하지 않는 경우는 제공되는 클래스 하나와 구조체 하나를 전역으로 선언해 놓고 사용하는 경우고, 문제가 발생하는 경우는 지역이나 힙에 할당해서 사용하는 경우였다.

OOP의 규칙중에 최대한 전역적인 요소를 제거해야 하는 바 절대 전역으로 선언해서 사용해서는 않되었기에 new에 의한 힙 할당으로 사용하려고 했지만 계속 뻗어 버리고.. 뭐가 원인인지도 모르고, 나중에는 제작자의 불순한 의도가 아니겠는가하는 의심까지 들고… 역시 세상에 꽁짜가 없다느니하는 생각이 들더랬다.

제작자의 불순한 의도로 방향을 몰고 가던중에, 소스 코드까지 제공했다면 그 불순한 의도 역시 소스 코드 어디엔가 나를 비웃고 있겠지 하는 생각에.. 반듯이 잡아 족치리라 생각하고 코드 한줄 한줄 디버깅 해 들어갔다. 문제를 발생시키는 함수는 asm 소스로 된 memcpy라는 Ansi C 함수였다. 다시 memcpy가 받은 인자의 값을 살펴보니 웬 쓰레기값?

불현듯… 몽롱한 과거 까까머리로 C/C++을 학습하던 시절에 전역 변수는 자동으로 초기화가 되지만 그외의 경우는 자동으로 초기화가 되지 않는다는 성경말씀이 생각나.. 이것이구나! 라는 생각에 제공되는 클래스와 구조체 중에 구조체의 맴버 변수의 값들을 모두 0으로 설정하고 다시 돌려보니 잘되더라는…. 원인을 알고보니 참으로 어처구니가 없더라는… 하지만 원이 무엇이듯 잘해결이 되니 참으로 감격스러웠다..

이런 감격에 오늘의 교훈을 잊지 않고자 기록에 남긴다. 역시 90%의 오류는 오직 내 안에 있다는 것을… 또한 다른 이의 선행을 확실한 근거 없이 오해하지 말자라고….

오라클 OCI 클래스

2004년에 만들어 썼던 OCI 클래스입니다. OCI는 Oracle Call Interface의 약자(방금전까지 C가 Common인지, C언어의 C인지 해깔렸다는 ㅡㅡ;)이구요.

별도의 ODBC, OLEDB 등과 같은 MS의 데이터연결을 위한 설정 없이 오라클 서버에 연결하여 쿼리를 날릴 수 있구요. OCI를 이용한 데이터 처리는 속도면에서 그 어떤 방법보다 빠릅니다.

오라클 예제 소스를 보고 클래스화한 것이구요. 메모리릭은 아직 발견하지 못했구요. 아래는 예제 코드입니다.

#include "OCIw.h"

int main() {
    COCIw OCI;
    OCI.OpenDB("oragis", "scott", "tiger");

    OCI.ExecuteDML("INSERT INTO TEST2 (NAME, AGE) VALUES ('김형준', 29)");
    OCI.ExecuteDML("INSERT INTO TEST2 (NAME, AGE) VALUES ('홍길동', 27)");

    OCI.Query("SELECT * FROM TEST2");
    OCI.DisplayRecords();

    OCI.CloseDB();

    return 0;
}

OCIw.h 파일에 선언된 COCIw 클래스가 주인공입니다. 자유롭게 사용하시길….. 버그나 개선점은 댓글로……

원하는 수의 배수로 맞춰주는 코드

어떤 수 x가 있다고 할때, x가 자신보다 크면서 원하는 수의 최소 배수인 수를 구하는 간단한 코드. 활용처는… 예를들어, 비트맵의 가로크기를 8의 배수나 4의 배수로 맞출때 요긴하겠네요.

size_t x = 1;
size_t align_ = 8;
cout << ((x + (align_-1)) & ~(align_-1));

x는 어떤 수, align_은 맞추고자하는 배수. 결과는 콘솔로 출력되겠죠..

[출처] Applied C++

수학식 구문해석(Mathematical Expressions Parser)

수학식 구문해석이란 예를 들어 쉽게 말해, “cos(0)+45″와 같은 수학식을 문자열 그대로 입력하면 컴퓨터가 이 구문을 해석하여 계산하고 계산결과를 반환하는 것이다.

필요에 의해 쓸만한 수학구문해석 소스를 검색해 본결과 다음 사이트에서 제공하는 Fast mathematical expressions parser 클래스가 가장 쓸만했다.

http://www.codeproject.com/cpp/FastMathParser.asp

예제를 분석해 보면 그 사용법을 금방 알 수 있겠지만, 나름대로 필요한 내용만을 빼내어 쉽게 정리하고자 한다. 혹, 다른 이에 급하게 수학식을 해석해야하는 기능을 구현하고자 할때, 이 글이 손쉬운 길잡이 되었으면 하는 바램이다.

먼저 위의 링크를 통해서 소스코드를 다운로드 받고 ParserLib 폴더의 muParser.sln 솔루션을 열어 컴파일 한다. 라이브러리를 Static이 아닌 DLL로 사용하고 싶다면 ParserDLL 폴더의 muParserDLL.sln를 열어 컴파일 하면 되겠지만, 여기서는 Static을 이용하였다. 별 어려움 없이 쉽게 컴파일 할 수 있을 것이다.

이제 컴파일된 라이브러리를 사용하기 위해 새로운 프로젝트(콘솔이든, MFC 든 상관없으며, 여기서는 콘솔로 하였다) 시작하고 추가 포함 디렉토리와 추가 라이브러리 디렉토리로 바로 전에 컴파일 했단 ParserLib 폴더를 잡아주고 추가종속성에 muParserDbg.lib를 입력한다. 이 경우는 Debug의 경우이고 Release의 경우는 muParser.lib를 입력한다.

여기서 정리할 내용은 간단히 주어진 수학식을 계산하여 계산 결과를 얻어 내는 것이다.

#include "muParser.h"
#include 

using namespace std;

int main() {
    char line[100];
    mu::Parser  parser;

    cin >> line;

    try {
        parser.SetExpr(line);
        cout << "결과: " << parser.Eval() << endl;
    } catch(mu::Parser::exception_type &e) {
        cout << "Msg: " << e.GetMsg() << endl;
    }
}

핵심이 되는 클래스는 mu 네임스페이스에 있는 Parser이고 수학식을 Parser의 SetExpr 맴버함수를 통해 전달해 주고, Eval 맴버함수를 통해 결과를 얻는다. Eval 맴버 함수는 옳바르지 않은 수학식일 경우 exception_type 예외를 발생하므로, 이 예외를 잡아 처리해 주면 된다.

사용할 수 있는 수식은 아래 두 표를 참고하기 바란다. 거의 대부분의 수학식과 이진연산식을 사용할 수 있으며, 개발자가 원하는 식을 직접 구현해 넣을 수 있다.

간단히 쓸만한 수학식 구문해석 클래스에 대해서 살펴보았고, 더 자세한 것에 대해서는 직접 다운로드 받은 예제를 통해 분석해보시길 바랍니다... 분명히 Fast mathematical expressions parser 라이브러리는 많은 사람들의 좋은 평가만큼이나 쓸만한 라이브러리가 틀림없습니다.

작업표시줄의 “시작” 버튼 위치 이동시키기

옛날 델파이(Delphi) 할적에 Window 컨트롤에 대해 이런 저런 장난을 많이도 쳤었는데, VC++로 전향한 이후에는 그런 장난을 하지 못했습니다. 오늘 한번 VC++를 가지고 컨트롤 장난질을 해봅니다. 이미 식상한 내용이긴 합니다만…. 모처럼 코딩(한달넘게 못해뜸)을 하면서 머리에 기름칠(ㅡㅡ;)도 좀 할겸해서… ㅋ

전역 변수입니다. (굳이 전역을 빼지 않아두 될 것도 있습니만..)

HWND starthandle;
CWnd StartButton;
CRect rect;
int nWidth, nHeight;

“시작” 버튼을 이동시키는 코드입니다. 버튼 컨트롤에 대한 클릭 이벤트에 넣으면 적당하겠군요.

starthandle = ::FindWindowEx(0, 0, "Shell_TrayWnd", NULL);
starthandle = ::FindWindowEx(starthandle, 0, "Button", NULL);

StartButton.m_hWnd=starthandle;
StartButton.EnableWindow(TRUE);
StartButton.GetWindowRect(&rect);
nWidth = rect.Width();
nHeight = rect.Height();

StartButton.MoveWindow(nMove,0,nWidth, nHeight ,TRUE);
nMove+=10;

“시작” 버튼을 가지고 장난을 쳤으면 이제 다시 원상복귀를 시켜놔야겠죠? 🙂

starthandle = ::FindWindowEx(0, 0, "Shell_TrayWnd", NULL);
starthandle = ::FindWindowEx(starthandle, 0, "Button", NULL);
StartButton.m_hWnd=starthandle;
StartButton.MoveWindow(0,0,nWidth,nHeight,TRUE);

음.. 별 쓰잘때기 없는 거죠? ㅋ 하지만 위의 내용에 제법 요긴한게 있긴 합니다. 윈도우 클래스를 이용해서 윈도우 핸들 구하는 방법도 나와 있구요.. 윈도우 핸들가지고 객체화(OOP –;)해서 나중에 요긴하게 두루 두루 써먹는 기법도 나와있네요..

개인적으로는 이제 제발 좀 코딩을 즐겁게 해보자는 취지에서리…. 올려봅니다.