'프로그래밍'에 해당되는 글 9건

  1. 2011.01.28 CentOS 5.5 에서 Python 2.7.1 + twisted + django 설치 쉘 스크립트
  2. 2009.05.20 온라인으로 프로그래밍
  3. 2008.04.03 마인드맵 툴을 만들었습니다 (3)
  4. 2008.03.31 Dodge, 뷃뗍, 총알피하기, 포인터 능엄경 (3)
  5. 2007.12.30 파이썬용 스프링노트 모듈
  6. 2007.12.29 파이썬에서 스프링노트 API 사용 (1)
  7. 2007.12.15 메모리가 주륵주륵
  8. 2007.11.20 삼각형 - 평면 충돌
  9. 2007.06.13 C++ 추상 클래스와 포인터 캐스팅, 다중상속 ㅅㅂㄹㅁ (11)

CentOS 5.5 에서 Python 2.7.1 + twisted + django 설치 쉘 스크립트

프로그래밍 2011. 1. 28. 17:40
#!/usr/bin/sh

PY_VER=2.7.1
PY_PACKAGE_VER=2.7
PY_INSTALL_PATH=/opt/python2.7.1

su
wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.1-1.el5.rf.$HOSTTYPE.rpm
rpm -Uhv rpmforge-release-0.5.1-1.el5.rf.$HOSTTYPE.rpm

yum -y groupinstall 'Development Tools'
yum -y install openssl-devel* zlib*.$HOSTTYPE

wget http://sqlite.org/sqlite-amalgamation-3.7.3.tar.gz
wget http://python.org/ftp/python/$PY_VER/Python-$PY_VER.tgz
wget http://pypi.python.org/packages/$PY_PACKAGE_VER/s/setuptools/setuptools-0.6c11-py$PY_PACKAGE_VER.egg

cd
tar xfz sqlite-amalgamation-3.7.3.tar.gz
cd sqlite-3.7.3/
./configure
make
make install

cd
tar xfz Python-$PY_VER.tgz
cd Python-$PY_VER
./configure --prefix=$PY_INSTALL_PATH --with-threads --enable-shared
make
make install

cd
echo "alias python=$PY_INSTALL_PATH/bin/python" >> .bash_profile
echo "alias python$PY_PACKAGE_VER=$PY_INSTALL_PATH/bin/python" >> .bash_profile
echo "PATH=\$PATH:$PY_INSTALL_PATH/bin" >> .bash_profile

cd
echo "$PY_INSTALL_PATH/lib" >> /etc/ld.so.conf.d/opt-python$PY_PACKAGE_VER.conf

cd
sh setuptools-0.6c11-py$PY_PACKAGE_VER.egg
cd $PY_INSTALL_PATH/lib/python$PY_PACKAGE_VER/config
ln -s ../../libpython$PY_PACKAGE_VER.so .

cd
source .bash_profile
/sbin/ldconfig

easy_install twisted
easy_install django

Trackbacks 1 : Comments 0

Write a comment


온라인으로 프로그래밍

프로그래밍 2009. 5. 20. 16:37
 브라우저만 가지고 이런저런 것들을 만들어 볼 수 없을까 고민고민 전전긍긍 엎치락뒤치락하다가 찾은 제법 쓸만한 사이트들입니다.

온라인 FTP 브라우저
FTPLive : http://www.ftplive.com/
Net2FTP : http://www.net2ftp.com/

Net2FTP 가 좀 더 이런저런 잡기능들이 많고, FTPLive는 딱 그냥 심플한 느낌.

온라인 편집기
Codepad : http://codepad.org/
jhp : http://www.3site.eu/jstests/jhp/
PHPanywhere : http://phpanywhere.net/

jhp는 자바스크립트 편집기 입니다. 좌측 하단 창이 Output 창이라서 코드를 작성한 뒤 마우스를 클릭하면 바로바로 실행이 되죠. 자동 들여쓰기, 구문 강조, 자동 완성까지 된다던데 어째 전 잘 안되네요. PHPanywhere는 구글링 좀 해보니 지금 있는 php 온라인 에디터 중엔 쵝오라던데 영 찝찝합니다. 제가 IE6 라서 그런가보죠?

끝으로 SplashUp!(http://www.splashup.com/) 이 갖추어지면 코딩에 이미지 작성 툴까진 온라인으로 대체할 수 있겠네요. 느리다는 것만 빼면.

빨리 배워서 재밌는 거나 만들어야 할 텐데.

Trackbacks 0 : Comments 0

Write a comment


마인드맵 툴을 만들었습니다

프로그래밍 2008. 4. 3. 01:38
사용자 삽입 이미지

마인드맵 프로그램 '마음난리'


'마음난리'란?
  • 여럿이서 하나의 마인드맵 작업을 하기 위한 프로그램입니다.
  • 로봇이 오픈API를 사용하여 아이디어 연상을 도울 수 있는 키워드를 추천해줍니다.
  • 마인드맵을 XML문서, 혹은 웹 오피스를 통하여 출판할 수 있습니다. (미지원)
 일단 시험적으로 며칠동안 서비스는 할 것 같은데 사실 서비스, 서비스 하기엔 건더기가 너무 없죠. 실은 매쉬업 경진대회를 목표로 연초에 작업하던 것을 최근 다시 꺼내서 만들어봤습니다. 스프링노트, 구글닥스 등 웹 오피스에 대한 출판 기능을 추후 추가할 예정입니다. 물론 그 추후가 언제가 될지는 저도 잘 모르겠네요.
 관심있으시면 꼭! 실행해보시고 의견 부탁드립니다.

파이썬+QT
 배포판을 보시면 알겠지만 파이썬을 이용하여 작업하였습니다. GUI는 PyQt4 라이브러리를 사용하였으며 py2exe를 이용하여 배포판을 만들었습니다. 프로젝트 시작시에는 Eclipse+pyDev를 사용하다가 중반 쯤 들어 다른 IDE를 써볼까 하고 찾아보았는데, 파이썬 멀티스레드 디버깅이 편한 IDE가 안보이더라구요.

XMLRPC
 서버/클라이언트 구조를 기본으로 상정하며 프로토콜은 XML-RPC를 사용합니다. 실제 마인드맵 데이터는 XML DOM을 통하여 관리하고 있습니다. 때문에 성능의 저하가 있을지 모르겠습니다. 서버는 역시 파이썬으로 Twisted라는 웹 프레임워크를 사용하여 구축하였습니다.
 
OpenID
 안보이게 이쁘게 처리하고 싶었는데 오픈아이디의 인증방식 자체가 어쩔 수 없이 한 번은 사람 손을 타게 되어 있어서, 어쩔 수 없이 새 창을 띄우는 방식으로 조금 더럽게 처리할 수 밖에 없었네요. 대신 로그인의 수고라도 조금이나마 줄이고자 로그인했던 아이디를 기억하는 옵션을 추가해두었습니다.

OpenAPI
 주된 기능으로 다음의 문맥 키워드 추천, 네이버의 연관검색어, 구글의 웹 검색을 이용했습니다. 직접 마인드맵을 작성해보시면 어떻게 사용되었을지 지레 짐작이 가실 겁니다. 그리고 외국의 오픈API 중에 Lingr라는 채팅API가 있어서 시험삼아 넣어보았습니다. 프로토콜로는 json을 이용하며 외국이라 그런지 만족스러운 속도는 아닙니다. 어떻게든 사용자들에게 커뮤니케이션 수단을 제공하고 싶어서 넣은건데…. 나중에 Skype API라도 쑤셔볼까하는 생각이 드네요.

유니코드, 영어
 기본적으로 프로그램 내에서 UTF-8을 통하여 모든 문자열을 처리하도록 되어 있습니다. 그런데 Eclipse IDE는 에디터 창이 조금 이상한 탓인지 한글이 들어간 소스를 저장할 경우 다음 번에 파일을 열 때 산산조각이 나 있더군요. (pyScripter나 EricIDE같은 경우에는 별 문제가 없었는데 EclipseIDE의 문제인 것 같습니다.) 그래서 작업의 편의를 위하여 코드 내의 문자열은 영어로 입력했습니다. 짧은 영어실력이 만천하에 드러나겠네요. 영어집중교육 등록해야겠다.
 유니코드가 참 여러군데에서 발목을 걸고 넘어지더라구요. 검색결과, 위젯의 문자열에서부터 quote해야할 문자열의 인코딩 문제까지…. 정말 인코딩의 가시밭길을 헤쳐나온 기분이었습니다.

Lingr가 속도가 느린 관계로 채팅을 배제한 상태입니다.
참. 마인드맵 메뉴는 오른쪽 버튼을 누르시면 됩니다.
적절한 테스트를 거치지 못해서 자꾸 글을 수정하게 되네요.

Trackbacks 2 : Comments 3
  1. Favicon of http://onechu.net BlogIcon WantU 2008.04.03 10:11 Modify/Delete Reply

    아직 안 써봤지만, 기획자 협업에 아주 좋은 툴이 될 것 같습니다.

    써보고, 트랙백 달도록 하겠습니다. 좋은 프로그램 감사합니다.

  2. Favicon of http://onechu.net BlogIcon WantU 2008.04.03 10:17 Modify/Delete Reply

    죄송하지만, 사용법과 설치법 좀 올려주세요;;

  3. Favicon of https://www.ikpil.com BlogIcon 최익필 2008.07.28 02:28 신고 Modify/Delete Reply

    게임 할려고 했는데 .. 안됩니다..

Write a comment


Dodge, 뷃뗍, 총알피하기, 포인터 능엄경

프로그래밍 2008. 3. 31. 10:25
사용자 삽입 이미지
invalid-file

(다운로드, Win32 바이너리)


 [8시간 내에 어떻게든 만들고야 말겠어!]
프로젝트 그 첫번째, 유명한 게임을 리메이크해보았습니다. 첫번째 8시간 프로젝트는 시간을 초과해버리고 말았습니다. 초반 4시간까지는 객체 설계나 기본 설계 까지는 빠른 속도로 진행가능했는데, 비트맵 뿌리는 부분에서 갑자기 주춤해서 시간이 너무 오래걸렸네요. (알고보니 오타 때문이었음.) 거기다가 펑크터 삽질에, 괜시리 최적화된 알고리즘이니 뭐니 생각해낸답시고 시간을 질질 끌다보니 어느덧 8시간을 넘어 10시간, 11시간. 절망했다!!

시간초과원인 분석
- functor 구현 시도에서 삽질 (결국 functor 포기)
- 적절한 탄환 배치 방법에서의 난항 (극좌표, 평면좌표를 헤매다가 적당한 눈속임 알고리즘으로 땜빵)
- 시간초과로 인한 졸음크리, 계속된 오타
- 속 안녕, 절망선생 13화

그리고 포인터 능엄경 [ 링크 ]

Trackbacks 0 : Comments 3
  1. Favicon of https://blog.mastojun.net BlogIcon Mastojun 2008.03.31 11:24 신고 Modify/Delete Reply

    어렵다 ㅠ_ㅠ ㄷㄷ

  2. Favicon of https://yurihan.tistory.com BlogIcon 유리한 2008.06.16 01:53 신고 Modify/Delete Reply

    뭐야..

    내 블로그 링크는..;;

Write a comment


파이썬용 스프링노트 모듈

프로그래밍 2007. 12. 30. 21:16

설명

  • 파이썬스프링노트 모듈로 CRUD만을 지원하는 간단한 구조입니다.
  • CRUD 작업 함수는 요청된 페이지를 문자열로 반환합니다. (XML 텍스트)
  • Delete의 경우에는 반환값이 없습니다
  • 사용자 설정을 위한 springnote.conf 파일이 필요합니다.
[springnote]
open_id: open ID
user_key: user key
app_id: application ID
app_key: application key

멤버함수

  • httpReq(method, uri, data=None): 스프링노트에 대한 HTTP REQUEST
  • createPage(): 사용자 노트에 새 페이지를 만듭니다.
  • getPages(): 사용자 노트의 페이지 전체(pages)를 읽어옵니다.
  • getPage(page_id): page_id에 해당하는 페이지를 읽어옵니다.
  • updatePage(page_id, title, memo): page_id에 해당하는 페이지의 제목을 title로, 내용을 memo로 변경합니다
  • deletePage(page_id): page_id에 해당하는 페이지를 삭제합니다
  • getTop(): 사용자의 시작 페이지(모든 페이지의 상위 페이지)의 id를 얻어옵니다.

페이지 생성

  • createPage() 는 현재시각을 제목으로 하여 새 페이지를 생성하고 생성된 페이지의 내용을 문자열로 반환합니다.

예제

  • 새 페이지를 생성하고 일련의 내용을 채워넣는 코드 (python 2.5 에서의 ElementTree를 이용하여 XML 파싱을 하였습니다.)
comm = SpringNote()
no_newpage = XML(comm.createPage()).findtext('{http://api.springnote.com}identifier')

title = '솔로라서'
memo = '행복해요ㅠㅠ'
comm.updatePage(no_newpage, title, memo)

소스코드

이 글은 스프링노트에서 작성되었습니다.


 파이썬용 모듈이 페이지 생성이 불가능하길래 새로 작성해보았다. 스프링노트에 블로그로 보내기가 있길래 한 번 티스토리로 쏴봤는데 의외로 놀라울 정도의 퀄리티였다. 하지만 코드블럭에서 조금 문제가 발생. 결국 조금 손을 봐주는 걸로 끝냈다. 사실 참고가 된 소스를 살짝 리버전한 정도에 불과하다. 반성! 파이썬이 참 재밌다. 취직하고싶다.

Trackbacks 0 : Comments 0

Write a comment


파이썬에서 스프링노트 API 사용

프로그래밍 2007. 12. 29. 02:54
링크 : http://nakada.springnote.com/pages/400945

 스프링노트 메쉬업을 작성해보기 위해 파이썬 스프링노트 API 모듈을 찾아보았다. 오픈마루 스프링노트 API 공식 도큐멘트에 링크되어 있는 파이썬 예제는 9월자로 스프링노트 인증방식이 바뀌기 전의 예제였다. 약간의 구글링 끝에 링크에 위치한 문서를 찾았지만 실제로는 ElementTree의 Element의 tag가 "{http://api.sptringnote.com}tagname" 같은 식으로 되어 있어서 위 문서 그대로는 ElementTree.findtext()를 통해서 제대로 파싱이 되지 않는 문제가 있었다. (왜일까?)

 PyDev를 쓰고 있어서 디버거를 돌려 볼 수 있었기에 망정이지 텍스트 에디터만 꼴랑 가지고 작업하고 있었으면 백날 삽질해도 알아차리지 못할 문제였다. 후덜. 갈 길이 멀다. 컴팩트한 프로젝트니까 후딱 끝내야지.


Trackbacks 0 : Comments 1
  1. Favicon of https://kkamagui.tistory.com BlogIcon kkamagui(까마귀, 한승훈) 2007.12.29 12:16 신고 Modify/Delete Reply

    와우~ 감사합니다. ^^)/~ 안그래도 파이썬에서 스프링노트에 접근하는 방법을 찾고있었는데... 좋은 자료네요 ;)
    감사히 잘 쓰겠습니다.

Write a comment


메모리가 주륵주륵

프로그래밍 2007. 12. 15. 10:49
MFC에서 부득이한 경우로, vector 나 기타 메모리 관리 클래스를 거치지 않은 채로 동적할당을 이용해서 객체를 사용하던 중 문제가 발생했다. 동적할당한 객체를 가리키건 포인터를 delete 하거나, 동적할당을 반복하던 중에 포인터가 붕 떠버리는 (dangle) 현상이 일어난 것.

거기다 이 객체들이 다른 힙까지 침범을 하는 건지... 이상한 부분에서 오류가 발생하기도 하고, 포인터가 엉뚱한 곳을 가리키기도 하고, 그래서 delete 가 말을 듣지 않는 등 일대 패닉이 일어났다. (heap overrun)

내가 싸질러 놓은 객체의 생명주기 하나도 관리하지 못하는 걸까 하고 좌절했지만 결국 객체의 멤버 초기화 함수 Clear() 를 정의하여 delete 직전에 호출해주기로 했다.

하지만 여전히, 안된다.

동적 할당 부분을 추가한 걸로 봐선 아무래도 힙 문제일 가능성이 높다. OTL

Trackbacks 0 : Comments 0

Write a comment


삼각형 - 평면 충돌

프로그래밍 2007. 11. 20. 22:31
며칠간 3차원 벡터로 정의되는 세 정점으로 이루어진 삼각형과 임의의 평면과의 교점들을 찾기 위해 고군분투하고 있었습니다. (삼각형-평면 충돌) 평면과 각각 정점과의 거리를 구한 값들(각 정점에 해당하는 세 개의 값)의 부호를 검사하는 것은,

#define ISALLSAMESIGN(x, y, z) ( ((x > 0) == (y > 0)) && ((y > 0) == (z > 0)) )

과 같은 식으로 처리할 수 있었는데, 이것만으로는 어떤 정점이 평면의 다른 방향에 존재하는지(세 값 중에 어떤 값이 나머지 두 값과 다른 부호를 가지고 있는지) 알 수가 없더라구요. 흑흑.

그래서 과연 어떤 값이 혼자 튀는지 검사할 수 있는 방법을 몇가지 생각해봤습니다. 매크로로 나타낼 수 있을 정도로 간단하면 좋을텐데. a, b, c를 넣으면 결과값으로 n번째 수가 부호가 다르다고 말해줄 수 있는 그런 놈이요. 일단 간단하게 생각해서 세 값의 부호를 각각 0과의 비교를 통해서 boolean으로 나타낼 수 있다고 생각했습니다. 그리고 세 개의 boolean 을 나열하면 3bit의 정수(0 ~ 7)로 나타낼 수 있겠죠.
세 부호가 같은지 판별하기 위해서는 이 결과값이 111(7)이나 000(0)인 경우만 추려내면 될 겁니다. ( result%7 == 0 ) 하지만 문제는 그 반대에서 조금 더 뻗어나가죠. 세 개의 bit 중에서 다른 두 bit 와 다른 bit 의 서수(ordinal)을 알아내야 합니다. 어쩌죠? (….)

#define WHOISTHECRIMINAL(a, b, c) ( (a*b < 0) + (b*c < 0)*2 + (c*a < 0)*4 )

생각한 방법은 결과값 3bit 를 가지고 0과 7과의 비트연산을 통해서 2bit의 값(0, 1, 2)을 얻어 그것을 서수로 사용하는 것이었습니다. 이것 역시 비교문을 쓰지 않기 위해서 생각해 낸 방법입니다. 하지만 대체 어떻게 연산해야 001 ~ 110 의 값을 차례대로 서수로(그것도 순차적인 서수가 아닌 0, 1, 2, 2, 1, 0 의 순으로) 바꿀 수 있는 걸까요? 적잖이 생각해보았지만 이건 좀 어려울 것 같습니다.

그런데 문제는 이거죠. 구현도 중요하지만 성능도 중요한 게 문제죠. CPU 비용이 얼마나 작은지. 결과값의 신뢰도가 어느정도인지. 고심(하면서 딴짓)하던 끝에 ary[] = { 0, 1, 2, 2, 1, 0 } 으로 배열을 선언하고 위의 결과값을 배열의 첨자로 사용하는 방법으로 결정했습니다. 제가 만들고 있는 프로그램은 데스크탑에서 실행될 거고, 메쉬의 모든 삼각형에 대해서 행해질 연산이니까요. 네.


Trackbacks 0 : Comments 0

Write a comment


C++ 추상 클래스와 포인터 캐스팅, 다중상속 ㅅㅂㄹㅁ

프로그래밍 2007. 6. 13. 22:41
상황설명

A라는 부모 클래스를 만들고, 이 A라는 클래스의 포인터인 A* pA 를 인자로 하는 foo(A* pA)를 정의해서 사용중이었다. 이 함수의 인자로는 A를 상속한 B나 C클래스를 예상할 수 있으며, 이 B와 C클래스는 I라는 순수 가상함수를 상속한 다중상속 객체들이었다. I는 순수가상함수인 Vfoo()를 가지고 있었다. C는 생성자에서 A의 함수(가상함수가 아니다)를 호출한다.

사용자 삽입 이미지

이런 상속관계 (수정)


vector<I*> vt;

...

C* pC = new C;
I* pI = (I*)pC; // C* -> I*
vt.push_back(pI);

...

A* pA = (A*)vt[0]; // C* -> I* -> A*
foo(pA);

...

foo(A* p_pA)
{
    I* pI = (I*)p_pA; // C* -> I* -> A* -> I*
    pI->Vfoo(); // 여기서 문제발생
}

문제발생

문제는 C형 인스턴스를 가리키는 A형 포인터 pA_dir_C를 foo(A* pA)의 인자로 넘겨주면서 일어났다. foo(A* pA)함수 내부에서는 인자로 받은 pA를 (I*)pA 로 형변환하여 Vfoo()를 호출하는 루틴이 들어있었는데, 여기서 에러가 발생한 것이다. (6025 pure virtual function call)

Watch를 통하여 살펴보니 vftable의 문제였는지, Vfoo()가 아닌 엉뚱한 함수가 불려오더라. (다른 추상 클래스 I2에서 오버라이딩 된 가상함수였다.) 포인터 형변환에서 가상함수 테이블에 변화가 오는 것일까?

해결책

결국 C* -> I* -> A* -> I* 와 같은 여러 번의 형변환을 거치지 않고 C* -> I* 상태에서 pI->Vfoo() 식으로 형변환 단계를 줄여서 사용하였다. 정확히 말하면 문제를 해결한 것이 아니라 회피한 것이나 마찬가지다. 하지만 적당한 레퍼런스도 없고, 도와줄만한 사람도 없고 해서. 코드 길이는 좀 길어질지 몰라도 저런 식으로 함수를 통하는 단계를 줄여버렸다.

감상

쩐의 전쟁이 너무 재밌다.


Trackbacks 1 : Comments 11
  1. ProgC 2007.06.14 02:24 Modify/Delete Reply

    음... 추상화 인터페이스를 이용한 설계를 하시는거 같은데
    그림이 좀 잘못된 것 같습니다. 그림상으로 보면 I인터페이스가 B, C를 구현하는걸로 되어 있네요. 그 반대가 되어야 할 것 같습니다.

  2. 동숙이 2007.06.14 12:23 Modify/Delete Reply

    정확한 소스를 어떻게 되나요?
    궁금해서 코드를 만들어 봤는데..

    제가 한봐로는 문제가 없는거 같은데요.

    • Favicon of https://axnoah.tistory.com BlogIcon AxNoah 2007.06.14 18:54 신고 Modify/Delete

      그럼 저 자체로는 문제가 없다는 걸까요.
      6025 pvfc 문제는 생성자에서 가상함수 테이블 관련해서 일어나는 문제라고 하던데, 형 변환 과정에서 가상 테이블의 변화가 있는지 없는지를 몰라서요.

  3. Favicon of http://dcple.com BlogIcon chadr 2007.06.14 14:59 Modify/Delete Reply

    제가 봐도 코드상에 이상한점은 안보이는군요..

    저기 안보이는 "...."부분에서 뭔가 잘못된 일을 하지 않는가 싶군요.

    • Favicon of https://axnoah.tistory.com BlogIcon AxNoah 2007.06.14 18:55 신고 Modify/Delete

      ㅠㅠ 대체 어떤 게 문제인지 모르겠습니다.
      회피하고 말았네요.

  4. Nagne 2007.07.31 11:44 Modify/Delete Reply

    검색으로 지나가다가 소스를 보고 발목잡혀 글남깁니다...
    일단 소스는 좀 오류가 심각하네요....당연히 않됩니다...
    I* pI = (I*)pC; 이부분과
    vt.push_back(pI); 이부분과
    A* pA = (A*)vt[0]; 이부분이 잘못됐습니다..

    이부분이 문제 입니다.... 인터페이스 I와 단순한 부모클래스 A를 다중상속받아서 사용하고 있습니다...
    벡터에 저장할 때는 (I*) 형으로 변환하고 있군요..
    자 일단 다중상속 받는 순서가 I 가 먼저오고, A가 다음에 온다고 가정하겠습니다...
    pC 의 주소값이 0x1000 이라고 가정하구요....
    I* pI = (I*)pC;
    A* pA = (A*)pC;

    이렇게 했을때 pI의 값은 0x1000입니다..
    그리고 pA의 값은 0x1000+alpa 입니다...
    왜 그러냐구요...클래스 포인터의 형변환은 주소값을 바꾸는
    기능을 합니다....(short*) 를 (int*)로 형변환 하는것하고
    클래스의 포인터를 형변환 하는것은 아주 큰 차이가 있습니다.
    (short*)를 (int*)로 형변환 하는것은 reinterpret 캐스팅이라고합니다. 형변환한 주소값에 아무런 변화가 없습니다. 형변환 하지 않을 경우 컴파일러가 이부분 문제가 있어보인다며 확인할것을 강요하고 프로그래머가 형변환 코딩을 넣도록 강요하는 역할을 가집니다.

    그러나 클래스 포인터의 형변환은 완전히 다른 의미입니다...즉 해당 클래스로 형변환 하면서 주소를 계산을 하는것이죠....이때에 룰이 있습니다..
    두 클래스간에 상속관계가 전혀 없을때는 주소계산을 하지 않습니다. 이것도 reinterpret 캐스팅이라고 합니다.. 그리고 상속관계에 있을때는 포인터 형변환시에 static 캐스팅이 발생합니다..주소값을 계산해 버리죠,....

    I* pI = (I*)pC; // 여기서 static 캐스팅 됐습니다..

    C는 I를 먼저 상속받았다고 가정했으니..static 캐스팅했지만 값의 변화는 없을겁니다...
    만약 (A*)pC 하였다면 값의 변화가 옵니다.

    그런데...
    (A*)vt[0]; 요 부분에서 vt[0]의 형은 (I*) 형입니다. 그리고 I와 A는 아무런 연관성이 없습니다..
    때문에 여기서는 reinterpret 캐스팅이 발생합니다...
    즉, A* pA = (A*)vt[0]; 요 부분에서 pA가 정상적인 동작을 할려면 0x1000+alpa 로 저장이 되어야 하는데, reinterpret 캐스팅 되어서 pA에 저장된 주소값은 0x1000이 되어버린것입니다...그러면 pA를 이용해서 Vfoo()를 호출하면 I의 영역을 A의 영역처럼 사용하겠죠..숨은 버그입니다... 그리고 c++에서는 static_cast<> 연산자와 reinterpret_cast<> 연산자가 있어서 위와 같은 버그를 컴파일 타임에 잡아줄수 있게끔 하고 있습니다.. (I*) 와 (A*)는 C 타입의 형변환입니다..reinterpret 캐스팅과 static캐스팅의 구분이 엄격하게 따지고 들어야만 제대로된 코딩이 가능하죠....
    아 그리고
    foo() 함수 내부에서
    * pI = (I*)p_pA; 요부분도 reinterpret 캐스팅이죠...아무연관성 없는 포인터형으로 변환한 것이니깐요..

  5. Nagne 2007.07.31 12:07 Modify/Delete Reply

    위 코드를 수정한다면 다음과 같이 하면 될겁니다..

    vector<I*> vt;

    ...

    C* pC = new C;
    I* pI = static_cast<I*>pC; // C* -> I*
    vt.push_back(pI);

    ...

    A* pA = static_cast<A*>static_cast<C*>vt[0]; // C* -> I* -> C*-> A*
    //I와 C는 연관성이 있지만 I와 A는 연관성이 없기에 연관성 있는것으로 중간에 연결가능한 C를 거쳤다가 변환합니다..당연히 static_cast이어야 합니다..

    foo(pA);

    ...

    foo(A* p_pA)
    {
    I* pI = static_cast<I*>static_cast<C*>p_pA; // C* -> I* -> C* -> A* -> C* -> I*
    //마찮가지로 A* 에서 I*로 형변환 하는 사이에 C*로 정적 캐스팅합니다..
    pI->Vfoo(); // 이제는 정상동작
    }


    static_cast가 하는일은 베이스클래스로 형변환 할때는 차일드 클래스의 주소공간 중에서 베이스클래스의 주소를 찾아서 주소값을 바꿔주고, 차일드 클래스로 형변환 할때는 베이스클래스주소가 그 차일드 클래스로부터 정적 캐스팅하였을때 획득한 주소라고 가정하고 차일드의 주소를 계산하여줍니다...
    따라서 사실 위 소스코드는 정상 동작하지만...
    vector<I*> vt 가 B 클래스의 인스턴스의 주소도 같이 저장하는 벡터라면 여전히 버그가 존재한다는것 잊지마세요...
    일단 버그 상관 없이 동작시킬라면 B 하고 C가 I하고 A를 상속받는 순서를 똑같이 하여야만 하고, B저장했던것인지 C저장했던것인지 확실히 구분 가능하여야만 위 코드가 정상 동작할 겁니다...

    class I{}; class A{}; class X{}; class Y{};
    class B : public I,public A ,public X{};
    class C : public A,public I ,public Y{};

    만약 클래스 구조가 이딴식으로 된다면....위에 수정해 드린 코드로도 정상동작은 않됩니다...단 vt[0]가 B의 인스턴스로부터 저장된 것인지. C의 인스턴스로부터 저장된것인지 확실히 알수 있다면 위와 같은 방식의 형변환으로 충분할 것입니다...
    그럼 이만...

    그리고 더 궁금한거 있으면 yilove78@fme.co.kr 로 문의하세요....

  6. Favicon of http://wafe.kr/ BlogIcon wafe 2007.08.28 15:42 Modify/Delete Reply

    다중 상속에 대해서 검색하다 우연히 들렀는데, 이미 다른 분께서 해결책을 남기셨군요. ^^

    C++에서는 타입 캐스팅을 할 때 C 스타일의 캐스팅보다는 C++ 스타일의 static_cast, dynamic_cast, reinterpret_cast 를 쓰는 것을 추천하고 있습니다.

    C의 캐스팅에 비해 여러가지 의미가 첨가되어 있는 것이 C++의 캐스팅이기 때문에 캐스팅의 내용을 좀 더 명확하게 알고 구분해서 쓰라는 의미가 있고요, 또 글에 쓰신 것과 같이 부적절한 캐스팅에 대해서 컴파일러가 힌트를 줄 수 있기 때문입니다.

    • Favicon of https://axnoah.tistory.com BlogIcon AxNoah 2007.09.15 12:50 신고 Modify/Delete

      관련 글 들은 몇 번 읽은 적이 있는데, 아무래도 습관 탓인지 아직 익숙하지 않네요. 경험부족이 이런데서 나오나 ㅠㅠ 음. 컴파일러가 알려 줄 수 있으면 적극 활용해야겠네요.

Write a comment