박응호님
한글과컴퓨터 - 나모인터랙티브 - 고누소프트
http://hompy.dreamwiz.com/hopark/cgi-bin/main.cgi?cmd=m
http://blog.daum.net/hopark

정내권님
한글과컴퓨터 - 드림어플라이언스 - 엠트레이스테크놀로지
ttp://www.emtrace.com/
Posted by 창신다이

출처: http://ddaddajoo.com.ne.kr/apphis.html
::: 한글과컴퓨터 (아래아 한글)의 역사 :::

89년 1.0, 1.2, 1.3 출시

서울대를 졸업한 이찬진 씨는 알고 지내던 프로그래머 세 명(정내권, 우원식, 김형집)을 모아 한/글이라는 새로운 워드프로세서를 개발해 베타버전인 0.9판을 89년도 초반에 출시한다. 물론 이때의 베타버전은 소규모로 지인들에게 배포되었다고 하고(참고로 우리나라 컴퓨터 관련의 산 역사라 할 수 있는 메카인 청계천에 뿌려 졌다고 한다. 반응 좋았음. 그래서 이곳에서 사업성을 확인함. 테스트 용.), 최초의 상용버전인 1.0판이 1989년 4월 출시되면서 한/글은 세상의 빛을 보게 되었다. 5.25인치 2D (360KB)디스켓 3장의 용량으로 만들어진 한/글 1.0판은 용산 전자상가의 소규모 유통업체인 러브리컴퓨터 라는 회사를 통해 10만원의 가격으로 출시되었다. 물론 상용버전인 만큼 매뉴얼도 들어있었지만, 이때는 대량생산을 하지못해 링형 바인더로 묶여진 매뉴얼을 제공하는 등 매우 조악한 패키지 구성을 가지고 있었다고 알려져 있다. 이 때 당시에는 외국산 워드프로세서를 한글화한 프로그램들만이 존재 하였던 것이 현실이었기 때문에 이는 정말 획기적이었다고 하지 않을 수 없는 사건 중 사건이었다.

이렇게 출발하게 된 한/글은 이찬진, 정내권, 우원식, 김형집에 의해 만들어 졌다. 세 명이 프로그래머이고 이찬진씨가 실질적인 경영을 맡았다고 한다.


< 아쉽지만 아직 이전 버전의 플그림은 구하지 못했다.>

한글과컴퓨터라는 회사 이름을 달기 전에, 한/글의 1.2판, 1.3판이 출시된다. 주로 각주 등 편집, 인쇄 기능이 많이 향상되었다. 당시에 판매되던 한/글은 출력할 수 있는 해상도의 조건에 따라 레이저판, 도트판이 따로 나뉘어져 있었는데, 300DPI의 출력물을 찍어낼 수 있는 레이저판은 27만원, 180DPI의 출력물을 찍어낼 수 있는 도트판은 9만원의 가격으로 판매했다. 그리고 레이저판에는 불법복제를 막기위해 프린터포트에 꽃아야만 프로그램이 동작하는 하드웨어 키가 들어있었다.

91년 1.5 출시

91년 1월에 드디어 크게 성공한 상용제품인 1.5판이 출시된다. 가격은 이전과 동일하였으며 도트판과 레이저판의 두 종류로 나뉘어져 발매되었다. 이 때 이찬진씨가 한글과컴퓨터라는 회사를 열었으며, 한글문화원 사무실 내부에 4평짜리, 5000만원으로 설립된 회사가 자리를 잡으면서 본격적으로 외부 직원들을 영입하기 시작한다.

도트판의 경우 2D 디스켓 다섯장으로 이뤄져 있었으며 당시 컴퓨터들이 하드디스크가 없는 제품들이 대부분이라 한자사전을 쓰기위해 디스켓을 바꿔끼우고, 인쇄를 하기위해 디스켓을 바꿔끼우는 식으로 아주 불편하게 워드를 사용해야 했다고 한다.

당시의 한/글 1.5판은 지금의 워드프로세서와 비교하면 기초적인 수준의 기능이 들어있었다. 파란바탕화면에 고정된 글자크기(기본, 혹은 가로세로 2배확대)만이 입력가능했고, 기본적인 정렬기능, 선그리기를 이용한 표그리기 기능 정도만이 가능했다. 글꼴은 명조, 고딕, 필기, 샘물의 4가지 한/글 글꼴만이 들어있었다. 현재 Windows에 기본으로 제공중인 워드패드만도 못한 기능들을 가지고 있었다.

하지만 이때 이미 한/글은 옛한글, 외국어를 포함해 완성형 코드로 표현 불가능한 11172자의 한글을 모두 표현할 수 있었으며, 두벌식 글판뿐 아니라 세벌식390 글판도 지원하는 등 한글 입력시스템은 이미 거의 완성단계에 접어들어 있었다.


그리고, 몇가지 버그를 수정한 한/글 1.52판으로 이미 최고의 한글 워드프로세서라는 평을 받은 한글과컴퓨터는 제품의 성공으로 얻은 자금과 인력을 통해 기존 버전에서는 도저히 상상할 수 없는 기능을 갖춘 당시로서는 외국의 워드프로세서보다도 뛰어난 기능의 한/글 2.0을 92년 7월 발매하게 된다.

92년 2.0 출시

한/글 2.0은 레이저판과 도트판의 구분을 버리고, 일반용과 전문가용이라는 구분을 달고 출시된다. 가격은 예전과 동일하게 일반용은 9만원, 전문가용은 27만원이었지만 1.52 레이저판의 모든 기능을 2.0 일반판에서 구현할 수 있었기 때문에 가격은 1/3으로 내린것이나 마찬가지였다.

한/글 2.0가 한/글 1.52와 비교해서 달라진 점들은 다음과 같다. 첫번째로는 가로/세로 두배확대만 가능했던 글자크기 조정기능이 1포인트~127포인트까지의 가변크기 조정기능으로 업그레이드 되었다. 이 기능은 전문가용에서 최초로 도입한 윤곽선 글꼴 기능과 맞물려서 당시 한/글 1.52버전을 사용하던 사람들에게 충격으로 받아들여 졌는데, 127포인트로 화면에 가득차게 확대를 해도 깨지지 않는 글꼴을 본 많은 사람들을 많이 놀라워했다고 한다. 또한 컬러인쇄를 지원하기 시작했다. 그리고 최초로 표편집 기능, 다단편집 기능과 문서 형식에 구애받지 않고 틀(글상자, 그림 등)을 자유롭게 배치할 수 있게 해주는 기능이 생겨났고, 컴퓨터 프로그램 최초의 한글 맞춤법 검사기능을 탑재, 띄어쓰기 오류등을 정확하게 지적해주기 시작했다. 또한 하이퍼텍스트 방식의 도움말을 탑재하고 있었다.

이런 획기적인 기능을 추가한 2.0버전의 출시로 한글과컴퓨터의 명성은 더욱 오르기 시작하고, 소프트웨어 업계의 최고의 스타로서 한글과컴퓨터가 자리잡는 계기가 된다. 이러한 기능들의 추가로 인해 디스켓의 장수도 이전버전에 비해 2배 가까이 늘어났다. 물론 하드디스크가 없이는 사용할 수 없었고 전문가용 버전이 XT컴퓨터에서 돌아가지 않는 바람에 업그레이드 수요도 부추겼다.

이 때부터 묵향 등 한/글용 외부 글꼴패키지가 판매되기 시작하면서 인기를 끌게된다. 한/글의 성공으로 인해 한/글 글꼴 시장에도 활기를 띄는 긍정적인 영향을 끼치게 된 것이다. 하나워드나 보석글과 비슷한 타자기 수준의 품질로 전자출판과는 거리가 멀어보였던 한/글 옛버전과 비교했을 때, 매킨토시에서만 가능할 줄 알았던 한글 전자출판이 한/글 2.0으로 인해 IBM PC에서도 가능하게 된 것을 생각하면, 한/글 2.0은 한글의 기계화에 역사적인 공헌을 한 첫번째 작품이 된 것이다. 그리고 이 후에는 더 이상 한/글의 독주를 저지할만한 경쟁자가 나타나지 않게 된다.

93년 2.1 출시


93년 9월 한/글 2.1버전이 출시된다. 한/글 2.0과 비교했을 때 큰 차이는 없지만 글꼴을 그리는 알고리즘이 개선되어 인쇄된 문서가 좀 더 깔끔한 결과를 보여준다는 장점이 있었고, 프로그램상의 한계로 인해 존재했던 편집 매수 제한이 500쪽으로 늘어나면서 책 한권을 너끈히 찍어낼 수 있는 전자출판 프로그램으로서 자리를 잡게 된다. 그리고 모아찍기, 나눠찍기 등의 인쇄기능이 새로 추가되었고, 포스트스크립트 호환 영문글꼴 등 휴먼컴퓨터사의 글꼴이 추가되기도 했다. 전문가용 버전은 처음으로 32비트 버전으로 출시되었다. 이외에도 세세한 개선점들이 많았다.

멀티미디어와 윈도 환경의 보편화

마이크로소프트에서 한글 윈도우즈 3.1을 내놓으면서 멀티미디어 PC/홈 PC라는 용어가 본격적으로 퍼져나가게 된다. 사운드카드에서는 사운드 블라스터 16, 옥소리 WS16 등을 시작으로 음악시디 수준의 녹음/재생이 가능한 제품이 출시되었으며, 비디오카드로는 ET4000, ATI 마하64 등 동영상 가속과 6만컬러 이상의 동시출력이 가능한 비디오카드가 출시 되었고, CD-ROM이라는 대용량의 A/V 데이터를 담을 수 있는 미디어와 2배속 드라이브가 등장하였고, 이를 받쳐줄 한글 윈도 3.1 이라는 운영체제가 등장하면서 본격적인 멀티미디어 환경을 컴퓨터에서 구현할 수 있게 되었다.

이러한 멀티미디어 PC의 등장, 그리고 그에 따른 윈도 3.1의 대대적인 보급이 한/글의 미래에도 영향을 미치게 된다. 한/글이 갓 2.1판을 출시하고 도스용 2.5판 개발에 들어갔을 즈음 한글 윈도에서 동작하는, 윈도우즈의 장점을 한껏 살린 여러가지 한글 워드프로세서가 등장하기 시작한다. 한메소프트의 파피루스, 금성소프트의 윈워드, 마이크로소프트의 한글워드 5.0, 삼성전자의 훈민정음, 핸디소프트의 아리랑, 휴먼컴퓨터의 글사랑 등이 등장하면서 윈도용 워드프로세서는 한/글 3.0b 윈도용이 등장하기까지 춘추전국시대를 맞이하게 된다.

다른 업체들은 이미 윈도 3.1용 워드프로세서를 내놓고, 한/글에서 불가능한 멀티태스킹, OLE등의 다른 프로그램에서 만든 개체의 삽입 수정, 3차원 글꼴다듬기(글맵시/워드아트), 윈도용 트루타입 글꼴 호환, 9개 까지의 다중 문서편집(한/글은 그때까지 2개의 문서만 동시에 열수 있었음.) 등을 장점으로 내세우며 나름대로의 시장을 차지하고 있을 즈음, 한글과컴퓨터는 여전히 도스용 워드프로세서인 한/글 2.5를 개발하면서 시간을 천천히 끌어간다. 물론 윈도용 한/글도 동시에 개발하고 있다고 밝히기는 하지만, 아직까지 속도나 안정성 측면에서 부족하고 보급이 더딘 윈도 3.1용 워드프로세서의 개발에 적극적으로 참여하지는 않는 모습을 보인다. 한/글 때문에 한국의 윈도 보급이 다른 나라보다 더 느려졌다는 이야기가 있을정도로 당시 워드프로세서 시장에서 한/글의 힘은 강력했다.

94년 2.5 발표

그렇게 한글과컴퓨터가 끊임없는 버전업과 많은 프린터 드라이버와 글꼴을 개발해 나가는 도중에, 94년 SEK 전시회가 열리게 되고, 한글과컴퓨터는 그 행사에서 한/글 2.5를 발표 하게 된다. 당시 한/글을 홍보했던 SEK 전시회의 한글과컴퓨터 부스의 크기는 마이크로소프트같은 대형 업체에도 뒤지지 않을만큼 엄청났었고, 전시회의 프로그램 내용이나, 행사의 질에 있어서 좋은 모습을 보여주었다. 여기서 한글과컴퓨터는 한컴비젼 2000을 선언하였다.

한/글 2.5는 덧실행이라는 이름으로 애드온프로그램을 지원함으로써, 다양한 유틸리티들을 한/글 실행 도중에 실행할 수 있도록 하는 방식을 지원했으며(물론 멀티태스킹은 지원하지 않았음), 다른 프로그램 개발 업체에도 관련 제작툴을 공개하면서 작게나마 통합플랫폼을 지향하기도 했다.

또한 2.1 전문용을 업그레이드 한 2.5 기본판이 12만원이라는 가격으로 매겨지면서 가격을 50%가 넘게 인하하였다. 대신 확장팩을 출시하였는데 국내 최초의 중형 영한전자사전인 프라임영한사전, 신명시스템, 태시스템의 추가 글꼴 등을 15만원의 가격에 판매하였다. 또한 최초로 시디롬 버전을 추가 판매하기도 하였다. 이외에도 마우스를 본격적으로 지원하고 글꼴 변경시 변경 내용을 미리 확인할 수 있는 등 여러가지 작은 개선점들이 많이 있었다. 또한 윈도우즈로의 업그레이드를 고려하는 사용자들을 위해 한/글 2.5 구입자들에게는 윈도용 한/글 3.0 무료 교환쿠폰이 제공되었다. 또한 서울 정도 600주년 기념 타임캡슐에 한/글 2.5가 포함되는 영광을 얻기도 하였다.

한/글은 2.0 버전 이후부터 미국의 워드퍼펙트이라는 워드프로세서를 많이 참조하였다고하는데 기능의 구현이나, 조판방식 등에 있어서 많은 유사점이 있다고 한다. 마이크로소프트 워드가 있기 전까지 미국에서 최고의 워드프로세서였던 워드퍼펙과의 전락적 제휴를 통해 만들어진 윈도용 한/글 3.0이 몇 달 뒤 출시된다.

95년 3.0 발표

한/글 3.0판 윈도용이 95년 3월 출시되었다. 윈도용 한/글의 첫 출시는 윈도 95 출시와 함께 그 해 소프트웨어 시장에서 가장 큰 이슈가 되었다. 윈도용 한/글은 지금까지 등장했던 다른 윈도용 한글 워드프로세서와는 달리, 운영체제에 의존하지 않는 독립 인터페이스, 독립 입출력 방식을 채택하였다. 윈도용 한/글 3.0은 윈도 3.1의 기본 프로그램 모양를 따르지 않고, 넥스트스텝과 윈도 95의 인터페이스를 혼합한 형태의 프로그램 모양을 선보였다. 한/글 1.0 버전부터 거의 변하지 않았던 구닥다리 인터페이스를 기억하는 많은 사용자들은 한/글의 변신에 매우 놀라워했다.

또한 완성형 한글 코드만을 지원하는 윈도 3.1의 입력체계를 사용하지 않고, 도스용 한/글의 입력체계를 그대로 이식함으로써, 11,172자 현대 한글은 물론 옛한글까지 전부 표현할 수 있게 되었다. 예전부터 조합형 한글 체계를 통한 한글의 완전한 표현을 장점으로 내세웠던 한/글이니 만큼 당연한 선택이라고 할 수 있다. 그리고 기존 도스용 한/글의 글꼴을 그대로 사용할 수 있도록 만들었고, 단축키도 도스용 한/글의 것을 그대로 받아들임으로서, 도스용 한/글에 익숙한 사용자들이 손쉽게 한/글을 익힐 수 있도록 하였다. 물론 기존 도스용 한/글의 문서를 아무런 손상없이 그대로 읽을 수 있다는 장점도 있었다.

이렇게 기존 도스용 한/글의 커널을 그대로 윈도용으로 컨버전한 한/글 3.0은 도스용 한/글의 장점 위에 멀티태스킹, OLE 기능, 윈도용 글꼴 및 프린터 드라이버 지원, 글맵시 기능 등 윈도용 워드프로세서로서 꼭 필요한 기능들을 추가함으로서 빠른 속도로 도스용 한/글 사용자들을 끌어들이기 시작한다. 하지만 한/글 3.0에는 버그가 굉장히 많았다. 이는 32비트 코드로 작성된 한/글 3.0이 16비트 운영체제인 윈도 3.1에서 돌아가기 위해 필요한 Win32s 런타임이 불안정 했기 때문으로, 패치 버전인 한/글 3.0a에서는 어느정도 문제가 해결 되었지만 윈도 95가 출시되기 이전까지는 많은 불만의 대상이 되었다. 가격은 기본팩이 12만원으로 책정되어 2.5와 동일했으며, 2.5의 확장팩 내용을 담은 추가CD가 4만원의 가격으로 추가 인하되었다.

마지막 도스용 한/글 발표

그리고 도스용 한/글의 마지막 버전인 한/글 3.0 도스용이 그해 6월 출시된다. 도스용 한/글 3.0은 윈도용 한/글 3.0에서 편집한 파일을 변환없이 바로 읽을 수 있다는 장점이 있었고, 인터페이스가 이전 한/글 2.5에서 약간 개선되고 도구상자를 추가함으로써 좀 더 편리한 사용이 가능하게 되었다. 그리고 한/영 자동 변환 기능 및 빠른 교정기능, 하이퍼 링크(하이퍼텍스트)기능이 추가되었다. 한편 덧실행 기능이 더 강화되어 PC통신 에뮬레이터/공학용 계산기/CD플레이어 등을 한/글 내부에서 실행 할 수 있도록 하였다. 이 외에도 수채화라는 그래픽 편집/드로잉 프로그램을 도스용 한/그림이라는 이름으로 번들로 제공했으며, 타자연습 프로그램도 기본 제공했다. 가격은 기본팩+CD-ROM이 12만원의 가격으로 판매되었다.


3.0b 발표

윈도 95가 출시된 직후, 윈도용 한/글 3.0의 업그레이드 버전인 3.0b가 출시되었다. 기본 내용은 3.0과 동일하지만 윈도 95에서도 실행이 가능해졌고, 여러가지 버그가 수정되었으며, 온페이지 드로잉 기능이 추가되었다. 윈도 3.1에서의 한/글의 여러가지 문제점이 윈도 95에서는 해결됨으로서 이 때를 기점으로 한/글이 윈도에서 자리를 잡게되는 계기가 된다.

한/글 3.0b가 대중적인 성공을 얻고난 후, 한/글은 윈도용 워드프로세서로 완전히 성격을 탈바꿈한다. 더 이상의 도스용 버전 개발을 중단하고, 다음 버전인 윈도용 한/글 96의 개발에 모든 노력을 쏟아붓기 시작한 것이다.

마이크로소프트 오피스의 공략과 한/글 오피스

이 때, 파워포인트와 엑셀과의 통합을 무기로 한, 마이크로소프트 오피스의 국내 기업체 공략이 거세지기 시작한다. 그때까지의 최고의 오피스 슈트였던 로터스 1-2-3와 워드 퍼펙을 미국에서 완전히 물리친 마이크로소프트 오피스는 95버전까지만 해도 한글판의 불완전한 번역, 잦은 버그, 한/글 문서와의 미호환, 국내에서 굳게 자리잡은 한/글의 텃세 등으로 고전을 면치 못하다가 97버전에서 부터 VBA를 이용한 특유의 확장성, 네트웍을 통한 다중 사용자의 작업 공유 기능, 기존 프로그램에서 보여주지 못한 여러가지 사용자 편의 기능, 온페이지 드로잉 기능의 강화, 전세계 문서 호환 등을 앞세워 점차 기업체를 중심으로 사용자 수를 늘려가기 시작한다. 그 뿐 아니라 삼성전자라는 대기업의 자본을 발판으로 무섭게 성장해간 훈민정음도 한/글의 시장을 조금씩 잡아먹기 시작하면서 미처 기업 시장을 체계적으로 준비하지 못했던 한글과컴퓨터의 약점이 드러나기 시작한다.

한 편 이때 한글과컴퓨터도 한/글을 기반으로 한 오피스 슈트를 출시하는데, 이 첫 주자는 한/글 3.0b의 초기판에 저가로 번들(한/글 3.0b 구입자에 한해 3만원의 가격에 판매)된 로터스 1-2-3와 프리랜스 그래픽스이다. 물론 서로 다른 회사의 제품을 통합한 것인 만큼, 호환성에 약간에 문제가 있었고, 로터스 1-2-3와 프리랜스 그래픽스가 이미 마이크로소프트 오피스와의 경쟁에서 밀려나버린 제품들이라 그 파급력이 덜했지만 한컴이 마이크로소프트 오피스와의 경쟁을 위해 어느정도 준비를 해나가고 있었음을 보여주는 작품들이었다.

한/글 96과 한글과컴퓨터의 부진

그리고 그 다음해에는 다양한 소프트웨어와의 통합패키지로 선보인 한/글 프로 96과 한/글 오피스 96이 출시된다. 기본적으로 사용자 인터페이스를 비롯해 인터넷 문서 편집, 문서마당 등 다양한 기능이 업그레이드 된 한/글 96을 기반으로, 주소록, 타자연습, 폼프로세서 틀마름이, 팩스프로그램, 메일 프로그램 등 다양한 유틸리티를 추가한 종합 선물세트라고 할 수 있었다. 그리고 이에 더해 한/글 오피스 96에는 이전에 선보였던 로터스 1-2-3와 프리랜스 그래픽스의 업그레이드 판이 포함되었다.

하지만 대중적으로 어느정도 성공을 거둔 한/글 프로 96과는 달리 기업체 시장을 타겟으로 출시된 한/글 오피스 96은 포함된 로터스 1-2-3와 프리랜스 그래픽스 프로그램의 기능 미비로 인해 별다른 반향을 얻지 못하게 된다. 게다가 그나마 성공을 거둔 한/글 프로 96도 개인용 시장의 포화와 불법 복제등의 영향으로 이전 수준의 성공을 거뒀을 뿐 더 이상의 성장이 정체되면서 한글과컴퓨터의 미래는 점차 불투명해지기 시작한다. 한/글을 제외하면 한/그림, 한/아름, 한/맥등 출시한 여러 제품이 모두 실패했을 뿐 아니라 새롭게 진출한 인터넷 시장에서도 검색엔진인 심마니를 빼고 별다른 실적을 낳지 못하면서 점차 불황의 늪으로 빠져들게 된 것이다.

한/그림은 벡터용 드로잉프로그램으로, 저가에 상당히 뛰어난 성능을 발휘한 소프트웨어였지만 후속제품이 출시되지 못하고 어도비 일러스트레이터 등이 선점한 시장을 뺏어내지 못함으로서 개발이 중단되는 비운을 겪어야만 했다. 또한 심마니도 국내 최초로 개발된 한글 자연어 검색엔진으로 상당히 뛰어난 성능을 발휘하며 한 때 검색 사이트 순위 1위에 오르는 등 인기를 끌었으나 광고등의 수익유치에 실패하고 야후나 알타비스타 등의 국내 포털진출에 때맞춰 찾아온 한글과컴퓨터의 실적 악화로 데이콤에 팔리면서 후발주자인 네이버나 다음 등에 밀려나게 되었다.

당시 국내에서 최고의 프로그래머들이 모였던 한글과컴퓨터는 경영 능력이 그에 미치지 못하면서 한/글의 기능 발전, 새로운 사업진출이나 시장개척에 어려움, 또한 IMF한파를 겪기 시작하고 결국 회사의 규모를 점차 줄이면서 한 때 2-3백명 가까웠던 사원들이 대폭 줄어 나중에는 60-70명 수준의 조그만 기업으로 남게된다. 그러나 1996년에는 한때 성공한 벤처기업모델로 부각도 되었으며, 정보통신업계최초로 코스닥에 등록되는 저력을 보여주기도 한 해이다.

한/글 97

1996년 11월에는 한/글 96을 기반으로 중국어, 일본어 인터페이스 및 다국어 입력기를 채용한 한/글 국제판과 일본 시장을 목표로 한 한/글 일본판이 출시되었고, 1997년에는 한/글 97을 탑재한 한컴홈 97과 한컴오피스 97이 출시되었으나, 판매실적은 기대에 미치지 못하였다.

1998년 초에는 한글과컴퓨터가 마이크로소프트의 투자를 받는 조건으로 한/글 소스코드를 마이크로소프트에 넘기고, 더 이상의 한/글 개발을 중단하기로 하는 양해각서를 마이크로소프트와 체결해 큰 사회적 파장을 일으켰다. 국민적인 반대여론에 부딪친 한글과컴퓨터는 이 협상을 없던 일로하고 한/글 815버전을 출시하는 한편, 한글과컴퓨터의 이찬진 사장은 회사 실적 악화의 책임(불법 소프트웨어도 한몫 단단해 했다.)을 지고, 한글과컴퓨터의 사장직에서 물러났다. 이때 PC통신 서명운동본부와 한글지키기 운동본부가 설립되고, 범국민 성금보내기, 공개제안투자제의 1인 1소프트웨어 갖기, 한 소프트 회원 운동등의 여러 운동을 통해 한글과컴퓨터는 재기의 발판을 마련한다.

한/글 워디안

한/글 2.1이후, 한/글 97까지는 커널 기반에서 커다란 변화가 없었다. 이로 인해 파일의 호환성도 어느정도 유지되었고, 사용법에도 큰 변화가 없는 모습을 보여주었으나, 2000년 출시된 한/글 워디안은 모든 소스코드를 새로 작성함으로써 이전 버전과는 다른 모습을 보여주게 된다. (이는 마이크로소프트 측에서 한/글 97의 소스코드를 갖고 있다는 점이 한글과컴퓨터에게 부담으로 작용한 측면이 있다고 보여진다)

한/글 워디안은 250단계의 다단계 되돌리기/반복 기능을 지원하고, 변형 다단 편집, 표 서식 기능 강화, 에센스 영한사전 및 표준 국어대사전을 삽입하는 등 커다란 개선사항이 있었지만, 워디안에서 작성한 문서가 이전버전에서 읽어지지 않는 문제, 이전버전의 문서가 워디안에서 본래대로 읽어지지 않는 문제, 프로그램의 안정성 문제가 지적되었고, 변경된 인터페이스에 익숙해지지 못한 사용자들이 여전히 한/글 97을 계속 사용하면서 별다른 인기를 얻지 못했다.

한/글 2002

한/글 워디안을 기반으로 이전 버전 파일과의 호환성 문제 및 안정성 문제를 해결한 제품. 2001년 출시되었다. 이후 외국계 펀드와 당시 경영진과의 한글과컴퓨터사의 경영권 분쟁이 발생하였으며 현재 한글과컴퓨터는 프라임산업개발의 자회사로 편입되었다.

한/글 2004

XML 문서 지원과 공개키 기반 암호화, 스킨, 작업창 기능이 추가된 제품. 한/글 2004와 함께 출시된 한컴오피스 2004는 국산 스프레드쉬트인 넥셀과 자체 개발한 한컴슬라이드 2004를 포함함으로써 토종 오피스 슈트로의 제 모습을 갖추게 되었다. 아직 기능면에서는 마이크로소프트 오피스에 많이 밀리지만 가격이 저렴하고 마이크로소프트 엑셀, 파워포인트와 사용법이 비슷하며, 파일 호환도 가능해 주목받고 있다.

한/글 2005


1. 동일한 문서의 이력을 관리할 수 있는 버전 관리 기능
2. 같은 문서의 서로 다른 버전끼리 비교 가능함으로써, 간편하게 문서 변천 과정 조회 가능
3. 문서의 레이아웃에 영향을 주지 않는 메모 삽입 기능으로 원활한 의사소통 가능
4.인쇄 옵션에서 삽입된 메모의 인쇄 여부 설정 가능
5.형광펜 기능으로 문서의 중요한 부분을 표시할 수 있어 문서 회람 시 유용하게 사용할 수 있습니다.
6.문서 수정 시 자주 사용하는 취소선을 바로 넣을 수 있도록 도구 상자에 아이콘이 추가되었습니다.
7.문서구조정보로부터(XML Schema 지원) 기본 XML 양식 생성
8.XML 문서 작성 및 저장, 읽기 지원
9.한/글 XML 서식과 Database의 자유로운 연동 가능
10.한/글 XML 서식에 존재하는 데이터 값을 ODBC(Open Database Connectivity)드라이버가 존재하는 데이터베이스로 저장/삭제/검색 등의 기능 지원

11.OLE Automation과 Script를 이용한 타 프로그램(그룹웨어,EDMS 등)과의 연동성 강화
12.도구 상자에서 필요한 양식 개체를 본문에 쉽게 삽입 가능
13.아랍어를 입력하고 출력할 수 있는 R2L(Right to Left) 기능으로 손쉬운 아랍어권 문서 작업 가능
14.공개키(PKI) 기반의 암호화 솔루션을 사용한 중요 문서의 보안 문서로 저장하기 지원
15.대화상자에 자신만의 설정 값을 저장, 쉽게 사용 가능 (인쇄/글자모양/편집용지/다단/각주,미주/표셀속성 등)
16.기본 스킨 외에 한/글 97, 고전, 메탈 스타일 등 다양한 스킨 제공으로 취향에 맞는 스킨 적용 가능
17. 자주 사용하는 특수문자나 클립아트를 별도로 관리할 수 있으므로 더욱 편리한 작업 가능
18. 한자로 변환 기능 대폭 개선
19. 문서 찾기 인터페이스 개선
20. 편집 용지의 여백을 마우스로 조절 가능

21.한/글 인쇄 관리자 기능
22.투명 대화 상자 설정 가능
23.마우스 움직임을 스크립트 매크로로 만들어 사용 가능
24.상호 참조 기능을 통한 편리한 문서 관리
25.표의 대칭 뒤집기 지원
26.마우스를 이용한 동일 비율 크기 조절 가능
27.여러 셀에 걸친 대각선 및 배경 입력 가능
28.자동 채우기 데이터 사용자 추가 기능
29.다양한 기능의 작업 창을 이용한 빠르고 편리한 문서 작업 가능
30. 한/글 97의 편리한 기능 반영 (연결 인쇄 /수식 입력 방식 지원)
31.찾기 기능 강화
32.한국인이 자주 사용하는 문서 서식 2,500개와 한/글 전용 클립아트 3,000여개를 제공.

MS의 DOS 나 Windows에만 국한하지 않고 자체적인 Linux시스템을 가지고 그를 기반으로 하는 한/글 및 넥셀 오피스 등고 개발해오고 있다.

Posted by 창신다이
보호되어 있는 글입니다. 내용을 보시려면 비밀번호를 입력하세요.


서영은 노래...

2006. 10. 29. 15:42
Posted by 창신다이
아버지 말씀이 옳았다.
내가 고1때 홍정욱의 '7막7장'을 읽으며
어떻게 영어를 모르는 사람이 미국 최고의 사립고인 Choat에서 좋은 성적으로 졸업을 할수 있었으며
또 어떻게 한편의 드라마같이 하버드에 합격해 행복하게 꿈을 이루었는지 동경하며
나의 유학 또한 그러리라고 다짐했을때
아버지는 나에게 책 3권을 추천하셨다
아직까지는 대학에 모슨 인생의 초점을 맞춘 나이기에...
아직은 대학이 세상의 모든것이라 판단했던 나이기에...
난 호기심때문에 단숨에 그 책 3권을 읽어나갔지만
어떻게 좋은 고등학교 성적으로 멋진 일류대학교에 들어갔는지에 대해 적기보다는
대학 이후의 미국 삶에 대한 글을 적어놓았기에
나는 그 책들을 서랍 구석에 집어 넣고
다시 홍정욱의 7막7장을 한번더 읽었다
2년뒤 내가 정말 나쁜 성적으로 이대학 저대학을 갈까 망설이고 있을때
아버지는 대학 그 자체의 명성보다 거기에서 무엇을 얻어서
자신을 더 가치있게 만들지 생각해보라고 하셨다
랭킹높은 대학이면 다인줄 알았던 나는
아버지의 말씀을 들으며 새삼스럽기까지 했다
그때 아버지가 내민 책 3권...
2년전 내가 팽개쳐버린 책들을 아버지께서 다시 주셨다
나는 이번에 그책을 한권 한권 읽어나가기 시작했다
꿈꾸는 자는 멈추지 않는다 - 전성철 지음
한국 S대학을 졸업하고 군대를 갔다온 전성철씨는 미국 유학을 꿈꾼다. 그것도 명성높은 로스쿨! 자신이 한국에서 할수 있는 모든것을
해봤지만 결국에는 우선 미국부터 먼저가자라는 판단으로 미국에 온다. 하지만 LSAT로 들어가기는 턱없이 부족했던 자본과 영어. 밤새며
책보고 하루종일 일을 했지만 그가 지원한 4군데 대학(하버드, 노스웨스턴등 최고의 로스쿨)에서 모두 떨어지며 씁쓸함을 맛본다. 할수없이
두번째 선택인 미네소타 대학의 MBA 과정을 수료하던중 다시한번 지원한 미네소타 로스쿨의 합격을 받아 로스쿨을 다니게된다. 하지만 그
의 로스쿨 졸업은 평생 직업을 보장할수 없었기에, 자신이 가진 '한국인'이라는 장점을 찾아 뉴욕의 유명한 로펌들에게 편지를 보낸다. 수십
군데중 답장이 온곳은 단 두곳. 하지만 그는 포기하지 않고 있는힘 없는힘 노력해 뉴욕 맨해튼의 유명로펌인 Reid&Priest의 회사에 취직하
게 된다. 자신이 할수있는일을 다했기에, 유일한 외국인, 동양인으로서 최단기간에 로펌 이사(partner)로 승진하게 된다.
내가 매우 인상깊게 읽었던 부분은 바로 이부분이다.
"내 친구중 에드콕스 (Ed Cox)가 나에게 와 파트너 승진을 축하한다고 해줬다. 하지만 나는 안타까웠다. 콕스는 나의 친구이기도 하지만
파트너 승진의 라이벌이기도 했기 때문이다. 그가 과연 무엇이 부족했던가? 프린스턴대학을 나와 하버드 로스쿨을 훌륭한 성적으로 졸업
하고 前미국대통령인 리차드닉슨의 사위까지 된 그인데.."
하버드, 프린스턴, 스탠포드등 명문의 대학을 졸업한다고 다른사람보다 우위에 있다는 편견을 깨트려버리게 해주는 문장이었다.
나는 정직과 성실로 미국을 정복했다- 백영중 지음
백영중씨는 1930년대 미국으로 건너와 인디애나 대학에서 토목공학을 전공한 엔지니어로 수만은 창의적 기술과 공법을 개발, 5개의
미국연방 특허를 보유하고 있다. 특히 그가 개발한 주름잡이 빔은 세계적인 개발품으로 인정받고 있다. 그가 회장으로 있는 패코스틸은
아이빔생산, 판매하는 철강업체로 연간 매출액이 약 2억 달러에 달한다. 현재 미국 전체 경량철골 분야의 60%의 시장점유율을 차지하고
있다.
이 분도에게도 배울 점이 있었다.
"미국에서 돈보다 더 중요한것은 신용이다. 누군가를 믿을(Trust)수 없다면, 그 사람은 더이상의 가치가 없게된다. 그래서 나는 절대로
거짓말을 하지않는다. 비록 비지니스이지만, 조금의 이익을 위해 정직을 팔수는 없기 때문이다."
"내가 동양인이기 때문에 처음에는 꺼려하던 기업들이 차츰차츰 우리 패코스틸과 거래를 하려고 한다. 아무래도 지난 1년간 보여준 성과가
바탕이 되었지 않았나 싶다. 분명 처음에는 차별이 있었지만, 모든것이 신용의 보답으로 돌아왔다. 믿지 않는사람에게는 보여주면 되는것이다."
미국에서 신용이라는 것이 성공의 열쇠라는 것을 느꼈다.
아메리카를 훔친 여자 - 김영숙 지음
김영숙씨는 재미소아정신과 전문의이다. 물론 이분의 인생 또한 존경스럽지만 내가 더 자세히 본 부분은 바로 재미교표 '2세'들이다
김영숙씨는 딸2,아들1명을 놓으셨다고 이 책에 적혀있다. 더욱 놀라운것은 이 아이들이 자라면어 어떻게 미국사고가 한국 사고와 혼합되면
서 여러가지 트러블을 일으키는지 알게되었다. 심지어는 아이의 미국 joke 하나도 한국사람인 김영숙씨는 이해하기 힘들었다고 하셨다
여기서 나는 재미교포2세들은 자신들의 사고방식이 만들어진 계기를 간접적이게나마 배우게 되었고, 한국에서만 살았던 사람으로써는
이해하기 힘든 부분이 몇군데 있다는점, 하지만 그런 생활방식이 결코 나쁜쪽으로는 해석되어서는 안된다는점, 그리고 교포로서의 mind가
어떻게 개방적인 사고를 얻게 되었는지 이해하게 되었다. 미국에 가면 많은 교포들을 만날터인데 그들과의 교화가 조금더 쉽게 이루어 지지
않을까 생각된다
결론은 ..
내가 이 유학을 가는것
내가 미국에 가는것
모두가 나의 미래를 위한것이라는 것이다
대학을 위한것이 아니라
미래를 위한 것이다
나는 내가 미국가기전에 이런 책들을 접할수 있었는것이 정말 행운이라고 생각한다
여기 게시판에 힘들고 짜증나고 논쟁하는 글들을 적는 분들도
이글을 먼저 읽고 미국을 갔더라면
조금은 다른 사고를 할수 있었지 않았나 싶다
Posted by 창신다이
Posted by 창신다이

토익 대박 LC전문

2006. 10. 19. 10:10
Posted by 창신다이

현재완료의 오해

2006. 10. 19. 10:09
현재완료라고 해서 일이 완전히 완료되는거는 아니거든,
아직까지 일이 계속 진행되고 있다는걸 의미한다.
have been ~ing는 계속 진행하고 있다는 것을 강조하는 것일 뿐...

by jinswpobby
Posted by 창신다이
Posted by 창신다이
誠者,天之道也. 誠之者,人之道也
성자,  천지도야  성지자,  인지도야
(성실한 것은 하늘의 길이고, 성실하려고 노력하는 것은 인간의 길이다.)
Posted by 창신다이

malloc을 통해서 동적 메모리 할당을 할때,

char *a = (char*)malloc(17);

a를 위와 같이 17만큼만 할당 후,

fread(a, 1, 20, fp); 와 같이 할당 받은 사이즈 보다 많은 값을 읽고난 후

char *b = (char*)malloc(17); 했을때 예외가 발생함...

따라서 동적 메모리 할당시 사용하는 메모리를 잘 계산해서 사용할 것.

문제 발생 소스는 너무 커서 생략.

Posted by 창신다이

#include "stdafx.h"

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
   int a[5] = {1, 2, 3, 4, 5};
   int* pb = &a[3];

   cout << (-2)[pb] << endl;

   return 0;
}

이 코드의 결과는?

Posted by 창신다이

#include <iostream>

using namespace std;

class Base{
int a;
public:
virtual void func1(){
cout << "func1" << endl;
}
virtual void func2(){
cout << "func2" << endl;
}
};

class Derived : public Base{
int b;
public:
virtual void func1(){
cout << "D::func1" << endl;
}
virtual void func3(){
cout << "func3" << endl;
}
};

class Derived2 : public Derived{
int c;
public:
virtual void func1(){
cout << "D2::func1" << endl;
}
virtual void func3(){
cout << "D2::func3" << endl;
}
virtual void func4(){
cout << "func4" << endl;
}
};

int main()
{
Base a;
a.func1();

Derived b;
b.func3();

Derived2 c;
c.func3();

return 0;
}

가상함수 테이블 샘플
Base 클래스의 가상함수 테이블만 보인다.

Posted by 창신다이
원문: http://cafe.naver.com/dmz28x/111

extern의 사용법은 크게 두가지가 있죠.

1. 다른 파일에 선언된 변수나 함수를 선언할 때

◆ 기본적인 얘기

extern이라는 것은 저장공간에 대한 선언에 사용되는 키워드로서,
여러개의 소스파일에 대해서 작업할 때 필요한 것입니다.
무슨 얘긴고 하니... 쉽게 말해서 다른 파일에 선언된 변수가 있다
고 선언하는 겁니다.

[file1.cpp]
int x = 1;
int f() { /* do something */ }
int y = 2;
extern z;

[file2.cpp]
extern int x;
int f();
extern int y = 3;  // 링크 에러.
extern z;          // 링크 에러

void g() { x = f(); }

extern int x; 라는 줄은 정수 x가 여기서 정의(definition)되지
않는다는 것을 지시하며 단지 선언(declaration)을 해주는 일을 수
행합니다. 위에서 y는 링크시 에러가 나게 되는데, extern 키워드
를 사용하더라도 초기화를 하면 그 선언은 정의가 되기 때문입니다.
즉, y는 file1.cpp와 file2.cpp에서 모두 정의되게 됩니다. 반대
로 z는 두 파일에서 모두 선언만 되고 정의가 되지 않았기 때문에 역
시 링크에러가 나게 됩니다.

참고로 file2.c에서 f는 extern int f(); 라고 지정해도 상관없습
니다.

◆ const와 typedef

const와 typedef는 기본적으로 internal linkage입니다. 즉, 다
른 파일에서 영향을 받지 않는다는 것이죠. const에서 이미 살펴봤
죠? typedef도 마찬가지입니다.

const에서 다뤘던 포인터 예제는 적절하지 못한 예였습니다. -_-;
여기서 다시 보도록 하죠.

[t1.cpp]
typedef int T;
const char* pText0 = "SCV";
char* const pText1 = "marine";
extern char* const pText2;
extern char* const pText3 = "tank";
extern char* const pText4 = "zealot";

[t2.cpp]
typedef void T;
const char* pText0 = "SCV";
char* const pText1 = "lurker";
extern char* const pText2;
extern char* const pText3;
extern char* const pText4 = "dragoon";

T : t1.cpp에서는 int, t2.cpp에서는 void로 사용할 수 있음.
pText0 : 조심! const char*의 의미는 const char에 대한 const
가 아닌 포인터. 즉, const가 아님. 따라서 external linakage.
링크 에러.
pText1 : char* const의 의미는 char에 대한 const 포인터. 즉,
internal linkage. t1.cpp에서는 "marine", t2.cpp에서
는 "lurker"으로 잘 동작함.
pText2 : 양쪽 모두 선언만 되고 정의는 안함. 실제로 사용하게 되
면 링크 에러.
pText3 : t1.cpp에서 초기화를 했기 때문에 정의가 됨. "tank"
pText4 : 양쪽 모두 초기화를 했기 때문에 양쪽 모두 정의가 되서
중복 정의 에러가 생김.

◆ extern을 사용가능한 경우

그럼 마지막으로 어떤 경우에 static이, 어떤 경우에 extern이 사용
가능한지 정리한 표를 보죠. (from MSDN)

Construct                                static   extern
Function declarations within a block      No       Yes
Formal arguments to a function            No       No
Objects in a block                        Yes      Yes
Objects outside a block                   Yes      Yes
Functions                                 Yes      Yes
Class member functions                    Yes      No
Class member data                         Yes      No
typedef names                             No       No


2. 다른 언어로의 연결을 지시할 때

◆ 기본적인 얘기부터

가장 대표적인게
extern "C" int Calc(double, int, int);
이런 식으로 C의 함수를 선언하는 것입니다.

아시겠지만 C와 C++은 함수를 호출하는 방식이 다릅니다. 인자를 처
리하는 순서라거나 스택에서 관리하는 방법 같은게 다르죠. (자세한
건 다음 기회에...) 따라서 C++ 컴파일러에게 이 함수는 C++의 규칙
에 어긋나는 함수는 아니지만 사실은 C의 함수라고 알려줘야 C++ 컴
파일러가 실수하지 않고 처리할 수 있게 됩니다. (실제로 이 선언을
중요하게 처리해야 하는건 링커입니다.)
그리고 Fotran에서 만든 함수를 Visual C++에서 사용하기 위해서
도 extern "C"로 선언해야 하는 것 같습니다. VC++이 extern 다음
에 허용하는 문자열이 "C"와 "C++" 뿐이라네요. (제가 해본건 아니
라서...)

extern "C"
{
#include < string.h>               // C 헤더 파일을 포함
   int Calc(double, int, int);   // C 함수를 선언
   int g1;                       // 정의(definition)
   extern int g2;                // 선언(declaration,
not definition)
}

이렇게 해서 여러개의 선언을 묶어주기도 하죠.

참고로 아랫줄은 정의가 아니라 선언입니다.
extern "C" int g3;              // 선언(declaration, not
definition)

C코드를 만들면서 C와 C++에서 다 사용할 수 있도록 헤더 파일을 만
들기 위해서는 다음과 같은 방법을 사용합니다.

#ifdef __cplusplus
extern "C" {
#endif

// 실제 함수나 변수들의 선언

#ifdef __cplusplus
}
#endif

C++ 소스를 컴파일할 경우에는 __cplusplus 가 자동으로 정의되므
로 전처리기에 의해 extern "C" { } 선언이 들어가게 됩니다.

◆ 함수 포인터의 경우

case by case로 생각해보겠습니다. (책을 베끼겠습니다.)

typedef int (*FT)(const void* , const
void*);                // (1)

extern "C" {
   typedef int (*CFT)(const void* , const
void*);           // (2)
   void qsort(void* p, size_t n, size_t sz, CFT
cmp);       // (3)
}

void isort(void* p, size_t n, size_t sz, FT
cmp);            // (4)
void xsort(void* p, size_t n, size_t sz, CFT
cmp);           // (5)
extern "C" void ysort(void* p, size_t n, size_t sz, FT
cmp); // (6)

int compare(const void* , const
void*);                      // (7)
extern "C" int ccmp(const void* , const
void*);              // (8)

(1) FT는 (const void*, const void*)를 받고 int를 리턴하는
C++로 링크되는 함수.
(2) CFT는 (const void*, const void*)를 받고 int를 리턴하는
C로 링크되는 함수.
(3) cmp는 CFT 타입. 즉 C로 링크되는 함수. qsort도 C 함수.
(4) cmp는 FT 타입. 즉 C++로 링크되는 함수. isort도 C++ 함수.
(5) cmp는 CFT 타입. 즉 C로 링크되는 함수. xsort는 C++ 함수.
(6) cmp는 FT 타입. 즉 C++로 링크되는 함수. qsort도 C 함수.
(7) compare는 C++로 링크되는 함수.
(8) ccmp는 C로 링크되는 함수.

따라서... 다음과 같은 결과가 나옵니다.
void (char* v, int sz)
{
   qsort(v, sz, 1, &compare);      // error
   qsort(v, sz, 1, &ccmp);         // ok
   
   isort(v, sz, 1, &compare);      // ok
   isort(v, sz, 1, &ccmp);         // error
}

[The C++ Programming Language]의 설명에 따르면 C와 C++이 함
수를 호출하는 방법이 같을 경우에는 위의 에러들도 확장으로 인정해
줄 수 있다고 하네요. 참고하세요.

◆ 다른 언어와의 연결에 대한 조금 더 시시콜콜하고 Visual C++적
인 얘기

포트란이나 파스칼 함수에 대해서는 __stdcall 를 사용해서 선언해
줘야 합니다.
(모든 윈도우 API 함수들은 __stdcall을 사용해서 선언되어 있습니
다.)
함수의 선언 앞에 붙이는 PASCAL, WINAPI, CALLBACK이라는 선언자
는 모두 __stdacll이라는 의미를 가지고 있죠.
반면에 C나 C++의 함수는 기본적으로 __cdecl이 됩니다.

__cdecl로 선언된 함수의 경우 인자를 전달한 스택을 정리하는건 호
출한 함수(caller)입니다.
__stdcall로 선언된 함수의 경우 인자를 전달한 스택을 정리하는건
호출된 함수(callee)입니다.
양쪽다 인자는 오른쪽 인자부터 왼쪽으로 스택에 들어가지요.

그렇다면 스택을 정리하는게 누구인지가 왜 중요할까요?
다른 언어가 다 호출된 함수가 스택을 정리하니까 C나 C++도 똑같이
하면 편할 텐데요.

일단 치명적인 부분은 vararg를 사용하는 함수입니다. 가장 대표적
인게 printf죠.
printf 는 다음과 같은 형을 가집니다.
int printf(const char *format, ... );
... 는 인자의 수가 정해져 있지 않다는 뜻이죠? 하지만 인자의 갯수
나 종류같은게 정해져 있지 않기 때문에 호출된 함수가 스택을 정리하
는 __stdcall의 경우에는 제대로 청소를 할 수가 없게 됩니다. 따라
서 인자의 수가 정해져 있지 않은 함수는 __cdecl을 사용하게 됩니
다.

참고로 __cdecl의 경우에는 각 함수 호출마다 스택을 정리하는 부분
이 들어가야 하기 때문에 컴파일된 코드의 크기가 더 커질 수 있다고
합니다.

그리고 코드를 C++로 작성중이더라도 라이브러리 파일을 만들어서 다
른 언어에서도 사용할 수 있게 해주려면 extern "C"와 __stdcall
을 사용해서 선언해주는게 좋겠죠?

이런 부분에 대해 자세히 알고 싶으신 분은 MSDN에서 "Mixed-
Language Programming Topics"이라는 글을 참고하시기 바랍니다.
Posted by 창신다이

원문: http://blog.naver.com/baboneo/80007502224
union을 사용하면 공간 절약, 큰 놈 쪼개기 등의 장점외에도...

**

union SVertexf
{
   struct
   {
       float x, y, z;
   };

   float v[3];
};

...

SVertexf v;

// 인간적인-_- 구조체 멤버에 접근해서 직관적으로 값을 대입하기도 하고

v.x = 3.0;
v.y = 2.0;
v.z = 5.0;

...

// 요런게 편할 때는 또 요렇게 하기도 하고

glVertex3f(v.v[0], v.v[1], v.v[2]);
glVertex3fv(v.v);

**

행렬도 비슷하게 처리하면 직관성과 for나 while 등 Loop의 장점도 살릴 수 있어 좋다.

이때 한 가지 주의할 점은...

공용체 내 서로 다른 구조체에서 변수 이름 충돌 시 먼저 정의된 변수가 우선한다는 거다.
에러 안남! -_-
따라서 같은 크기의 구조체에서 대응되는 위치에 동일한 이름이 사용될 경우
아무런 오류없이 돌아간다. 하지만 다른 이름 짓기를 권장함!

Posted by 창신다이

char** pArrStr = new char*[10];
for (int i = 0; i < 10; i++) {
 pArrStr[i] = new char[20];
 sprintf(pArrStr[i], "Hello World - %d", (i + 1));
}

for (int j = 0; j < 10; j++) {
 cout << pArrStr[j] << endl;
 delete [] pArrStr[j];
}
delete [] pArrStr;
// [] 하지 않았을때 소멸자가 한번만 실행됨.
// 원시타입일 경우 차이 없음.

malloc 도 위와 같음.

추가.
동적할당 메모리 누수 체크

stdafx.h 파일과 같이 모든 소스에서 include 하는 파일에 추가.

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)

main() 에 추가.
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

Posted by 창신다이

C++에서 double형을 int형으로 casting해서 사용할 때 소숫점이 절산된다

#include
#include
using namespace std;

int main(void) {
double dt = 15.25-14.74;

cout << floor(dt * 100.0) << endl;
cout << (int)(dt * 100.0) << endl;

cout << floor(dt * 100.0+0.5) << endl;
cout << (int)(dt * 100.0+0.5) << endl;

return 0;
}

실행결과
50
50
51
51

문제는 위의 2개의 결과인데, dt값이 0.51이기 때문에 *100하면 51이되어서 51이 출력될 줄 알았는데 50이 출력된다. int casting을 하지 않으면 51이 나온다.
모든수가 그런것은 아니고 몇몇수가 그렇다.

A)dt 값이 0.51이 아닌 0.509xx 등등이 될 수 있다.
부동소수점 표현법은 근사치로만 사용할 수 있기 때문. dt 값을 %f 로 출력해보면 0.50999999999999979 이 나온다.

Posted by 창신다이

컴파일러

2006. 10. 18. 20:52

GCC for windows
http://www.cygwin.com/

Visual C++ 2005 Express Beta
http://lab.msdn.microsoft.com/express/visualc/default.aspx
IDE까지 포함, 날짜 제한

Visual C++ Toolkit 2003
http://msdn.microsoft.com/visualc/vctoolkit2003/
통합개발환경이 없음. VC++.NET 2003 컴파일러를 명령창에서 쓸수 있음.

Posted by 창신다이

1.virtual 로 선언을 하면 가상 함수로 설정이 된다.
2.가상함수로 설정이 되면 함수의 실행 모듈을 코딩하지 않아도 가
능하다.
3.가상함수로 설정할때 장점은 상위 클래스에는 필요가 없으나 하
위클래스에서 필요할경우 상위에 virtual로 선언하고 상위 클래스
로 모든 프로그램을 구동시킬때 사용한다.
4.객체를 후에 업그레이드 할경우 virtual 로 선언한후에 차후에
해당 프로그램의 기능을 넣는 방식에 해당한다.
5.객체 지향방식의 프로그래밍에서 발전 부분및 통합 연동의 대표
적인 기능

-sample-

#include <iostream.h>
#include <string.h>

class CGbtObject
{
protected:
int style;
int x1;
int y1;
public:
virtual void print();
void setdata(int s,int x,int y);
};

void CGbtObject::print()
{
cout << style << ",";
cout << x1 << ",";
cout << y1 << "\n";
}
void CGbtObject::setdata(int s,int x,int y)
{
style=s;
x1=x;
y1=y;
}

class CStrObject:public CGbtObject
{
public:
char str[20];
virtual void print();
};

void CStrObject::print()
{
cout << style << ",";
cout << x1 << ",";
cout << y1 << ",";
cout << str << "\n";
}
void main()
{
CStrObject a;
a.setdata(1,2,3);
strcpy(a.str,"test");
a.print();
}

1.클래스에서 내부에 있는 특정 맴버 함수만 외부에서 사용하고자
할때 static 로 선언한다.
2.static 로 선언되면 해당 함수는 내부 클래스의 맴버 함수들을
접근 할수 없는 독립 호출 함수가 된다.
3.사용불가 예
class CTest{
protected:
int data;
public:
static int getdata(int d)
{
d+data //사용 불가
};
};

-sample-

#include <iostream.h>
#include <string.h>
#include <stdio.h>
class CStr
{
public:
char string[80];
static char* Strcpy(char *d,char *s);
char *Strcpy(char *s);
};
char* CStr::Strcpy(char *d,char *s)
{
strcpy(d,s);
return d;
}
char* CStr::Strcpy(char *s)
{
strcpy(string,s);
return string;
}

void main()
{
CStr str;
char data[80],data2[80];
cin >> data;
CStr::Strcpy(data2,data);
cout << data2;
cin >> data2;
str.Strcpy(data2);
cout << str.string;
}

Posted by 창신다이

1. malloc
  - malloc함수의 리턴값은 요구한 메모리를 얻으면 메모리의 시작주소를 리턴해주고 얻지 못하는 경우에는 NULL을 리턴해 준다. NULL은 주소값이 없다는 것을 뜻한다.

2. malloc과 calloc의 차이
  - malloc함수는 요구한 메모리를 초기화 하지 않는 반면에 calloc함수는 요구한 메모리의 값을 0으로 초기화 해준다

3. realloc함수는 할당 받은 메모리의 크기를 변경하기 위한 함수이다. 재할당 받는 함수이다. 메모리의 크기를 크게하던 작게하던 상관은 없다. 다만 재 할당을 받아도 그전에 저장했던 내용은 저장이 된다.

4. 동적메모리를 왜 사용하는가???
  - 메모리에 누수가 생기면 시스템에 커다란 해를 끼칠 수 있다면 동적 메모리를 사용하지 않는 것이 좋다.

Posted by 창신다이

원문 : http://joinc.co.kr/modules.php?name=News&file=article&sid=105&mode=nested

이 문서는 C에 익숙하지만 C++ 에는 아직 익숙치 않은 프로그래를 위한 문서이다. 비록 이제 막 C++ 로 입문하고자 하는 C 언어 사용자의 "팁"수준의 지침서 정도가 되겠지만, C++을 꽤 사용했던 프로그래머에게도 몇가지 도움이 될만한 힌트가 있을것이다.

차례
1절. C프로그래머를 위한 C++
1.1절. 새로운 include 방법
1.2절. 라인단위 주석사용
1.3절. 간단하게 사용할수 있는 입출력 스트림
1.4절. 변수선언 위치제한
1.5절. 전역변수와 지역변수의 동일이름 사용
1.6절. 변수의 상호참조가능
1.7절. namespace 의 선언
1.8절. inline 함수의 사용
1.9절. 예외처리
1.10절. default 인자사용 가능
1.11절. Parameters Overload
1.12절. Operator overload
1.13절. template
1.14절. 메모리 할당/해제
1.15절. Class
1.16절. 생성자 / 소멸자
1.17절. 클래스 메서드의 선언과 정의 분리
1.18절. 객체의 배열
1.19절. 클래스 멤버변수의 static 선언
1.20절. 클래스 멤버변수의 상수선언
1.21절. this 포인터
1.22절. 상속
1.23절. 다중상속
1.24절. 캡슐화(은닉)
1.25절. 가상함수
1.26절. 파일스트림 처리
1.27절. 정형화된 출력
1.28절. 문자배열을 file 처럼이용하기

--------------------------------------------------------------------------------

1절. C프로그래머를 위한 C++
1.1절. 새로운 include 방법
C++ 에서는 헤더파일을 인클루드 시키기 위해서 새로운 방법을 사용한다. C++ 에서는 C의 표준 헤더파일을 인클루드 시키기 위해서 ".h" 확장자를 사용하는 대신에 ".h"를 생략하고 헤더파일의 가장앞에 "c" 를 붙여서 인클루드 시킨다. 제대로된 인클루드를 위해서 "using namespace std;" 를 포함시키도록 한다. 표준 C++ 헤더는 확장자를 생략하면 된다 - 생략하지 않아도 문제는 없지만 -.

물론 기존의 C 스타일대로 헤더파일을 인클루드 시켜도 문제는 없다. 그러나 어떤 컴파일러의 경우(gcc 3.x 와 같은) 디버깅 옵션을 켜놓은 상태에서 컴파일할경우 warning 메시지를 출력하기도 한다. // stdlib.h -> cstdlib
#include <cstdlib>
#include <iostream>

using namespace std;
int main()
{
   char *age = "25";

   cout << atoi(age) << endl;
}

--------------------------------------------------------------------------------

1.2절. 라인단위 주석사용
C 에서와 마찬가지로 // 를 이용한 라인단위 주석의 사용이 가능하다. #include <cstdlib>
#include <iostream>             // iostream 라이브러리 사용

using namespace std;           // 표준 라이브러리 namespace 지정
int main()
{
   char *age = "25";

   cout << atoi(age) >> endl; // 출력
   return 1;                  // 종료
}

--------------------------------------------------------------------------------

1.3절. 간단하게 사용할수 있는 입출력 스트림
C 에서는 간단한 화면/키보드 입출력이라도 꽤 번거로운 과정을 거쳐야 하지만, C++ 에서는 cout <<, cin >> 을 이용해서 간단한 입출력을 쉽게 처리할수 있다. #include <iostream>

using namespace std;
int main()
{
   int age;
   char name[32];
   cout << "hello world " << endl;
   cout << "your age : ";
   cin >> age;
   cout << "your name : ";
   cin >> name;

   cout << "Your input is " << name << ":" << age << endl;
}

--------------------------------------------------------------------------------

1.4절. 변수선언 위치제한
C 의 경우 변수 선언은 함수의 가장첫부분에서 이루어져야 한다. 만약 중간에 선언이 이루어진다면, 컴파일시 에러를 발생하게 된다.

C++ 은 어느 위치에서라도 선언해서 사용할수 있다. 이러한 점이 때로는 코드를 난잡하게 만들기도 하지만, 오히려 코드를 보기쉽게 만들어줄때도 있다. #include <iostream>

using namespace std;
int main()
{
   int a, b;

   cout << "A : " ;
   cin >> a ;
   cout << "B : " ;
   cin >> b ;

   int sum;
   sum = a + b;
   cout << a << "+" << b << "=" << sum << endl;
}

--------------------------------------------------------------------------------

1.5절. 전역변수와 지역변수의 동일이름 사용
C 에서는 전역변수와 지역변수가 이름이 같을경우 무조건 지역변수의 값만을 사용할수 있었으나(전역변수 값은 사용 할수가 없다), C++ 에서는 각각 구분해서 사용가능하다. #include <iostream>
using namespace std;

int my_age = 28;
int main()
{
   int my_age = 35;

   cout << "Local my_age " << my_age << endl;
   cout << "global my_age " << ::my_age << endl;

   return 0;
}
                       
--------------------------------------------------------------------------------

1.6절. 변수의 상호참조가능
다음과 같은 방법으로 하나의 변수를 다른변수에서 참조하여 사용하는게 가능하다. #include <iostream>
using namespace std;

int main()
{  
   int a = 200;
   int &b = a;

   b = 100;
   
   cout << "a is "  << a << endl;
   return 0;
}
                       

위의 코드를 실행시키면 100 이 출력된다.


--------------------------------------------------------------------------------

1.7절. namespace 의 선언
namespace 를 이용해서 변수의 선언이 가능하며 :: 연산자를 통해서 선언 없이 곧바로 변수의 이용이 가능하다. #include <iostream>
using namespace std;

namespace first
{
   int a;
   int b;
}
namespace second
{
   int a;
   int b;
}
int main()
{
   first::a = 100;
   first::b = 200;

   second::a = 400;
   second::b = 800;

   cout << first::a + second::a << endl;
   cout << first::b + second::b << endl;
}

--------------------------------------------------------------------------------

1.8절. inline 함수의 사용
간단한 함수들은 inline 으로 선언해서 사용함으로써 몇가지 잇점을 얻을수 있다. inline 으로 선언된 함수는 일종의 macro 와 같이 작동을 하게 된다. 즉 필요할때 불러오는 방식이 아니라, 코드에 바로 insert 된 효과를 준다. 이것이 주는 잇점은 코드가 약간 커지긴 하겠지만, 빠른 실행 속도를 보장해 준다는 점이다. #include <iostream>
#include <cmath>
using namespace std;

inline double mysqrt(double a, double b)
{
   return sqrt (a * a + b * b);
}
int main()
{
   double k = 6, m = 9;

   // 밑의 2개의 라인은 실행시에 완전히
   // 동일하게 작동한다.  
   cout << mysqrt(k, m) << endl;
   cout << sqrt(k*k + m*m) << endl;

   return 0;
}
                       

inline 인것과 아닌것의 차이를 비교해보고 싶다면, g++ -S 를 이용해서 어셈코드를 얻은다음에 직접 비교 해보기 바란다.

--------------------------------------------------------------------------------

1.9절. 예외처리
당신이 C에서 사용하고 있다면, for, if, do, while, switch 와 같은 키워드들를 알고 있을것이다. C++ 에서는 예외처리(EXECPTION)와 관련된 또다른 키워드들을 제공한다. 선택문 혹은 예외처리를 위한 좀더 직관적이고 손쉬운 프로그래밍 작업을 가능하도록 도와준다. #include <iostream>
#include <cmath>
using namespace std;

int main()
{
   int age;
   char *no_vote[] = {"없습니다", "있습니다."};

   cout << "당신의 나이는 ? ";
   cin >> age;

   try
   {
       if (age > 18) throw 1;
       else throw 0;
   }
   catch(int result)
   {
       cout << "당신은 투표권이 " <<  no_vote[result] << endl;
   }

   return 0;
}

--------------------------------------------------------------------------------

1.10절. default 인자사용 가능
함수의 인자를 사용할때 기본 인자를 설정할수 있다.  
#include <iostream>
using namespace std;

int mysqrt(int a, int b = 2)
{
   int c = 1;
   for (int i =0; i < b; i++)
   {
       c *= a;
   }
   return c;
}
int main()
{
   cout << mysqrt(5) << endl;
   cout << mysqrt(5, 5) << endl;
}

--------------------------------------------------------------------------------

1.11절. Parameters Overload
C++ 의 중요한 잇점중에 하나가 인자를 통한 함수 오버로드가 가능하다는 점이다. 오버로드 기능을 이용함으로써, 서로 다른 연산을 수행하는 함수를 하나의 이름으로 관리 가능 하도록 도와주며, 이는 코드의 유지/보수/가독성을 높여준다. #include <iostream>

using namespace std;

double add (double a, double b)
{
   return a+b;
}

int add (int a, int b)
{
   return a+b;
}

int main()
{
   cout << add(1, 2) << endl;
   cout << add(1.2, 2.4) << endl;
}

--------------------------------------------------------------------------------

1.12절. Operator overload
함수인자를 통한 오버로드 뿐만 아니라, 기본적인 연산자들의 오버로드역시 가능하다. 다시 말해서 연산자의 정의를 다시 내릴수 있도록 한다. #include <iostream>

using namespace std;
struct vector
{
   double x;
   double y;
};

vector operator * (double a, vector b)
{
   vector r;
   r.x = a * b.x;
   r.y = a * b.y;

   return r;
};

int main()
{
   vector k, m;
   k.x = 2;
   k.y = 4;

   m = 3.141927 * k;
   cout << "(" << m.x << "," << m.y << ")" << endl;

   return 0;
}
                       

연산자 오버로는 사칙연산자 외에도 +=, ++, [], (), << 등을 포함한 약 40개 이상의 연산자에 대해서도 가능하다. #include <iostream>

using namespace std;
struct vector
{
   double x;
   double y;
};

ostream& operator << (ostream & o, vector a)
{
   o << "(" << a.x << "," << a.y << ")" ;
   return o;
}

int main()
{
   vector k;
   k.x = 2;
   k.y = 4;

   cout << k << endl;
   cout << "hello "<< endl;

   return 0;
}

--------------------------------------------------------------------------------

1.13절. template
함수 오버로딩이 꽤 편하긴 하지만, 몇가지 불편함이 있다. 즉 인자의 갯수만큼의 함수를 만들어줘야 한다. 만약 int, float, double 연산을 위한 오버로드된 함수를 만들고자 한다면, 거의 똑같은 3개의 함수를 정의해야만 한다. template 를 사용하면 인자의 자료형에 관계없이 사용가능한 (범용한) 함수의 제작이 가능하다. #include <iostream>

using namespace std;

template <class T>
T mymin (T a, T b)
{
   T r;
   r = a;

   if (b < a) r = b;

   return r;
}

int main()
{
   cout << "Litle is : " << mymin(2, 100) << endl;
   cout << "Litle is : " << mymin(2.6, 2.4) << endl;
}

위의 템플릿을 이용한 코드는 꽤 괜찮게 작동하긴 하지만, 한가지 문제가 있다. 위의 코드는 인자의 타입이 동일해야 한다. 만약 인자가 각각 int, double 타입을 가진다면, 컴파일시 에러를 발생시킬것이다. 이문제는 템플릿을 선언할때 서로 다른 인자를 받아들일수 있도록 선언하면 된다. #include <iostream>

using namespace std;

template <class T1, class T2>
T1 mymin (T1 a, T2 b)
{
   T1 r, converted;

   r = a;

   converted = (T1) b;

   if (converted < a) r =  converted;

   return r;
}

int main()
{
   cout << "Litle is : " << mymin(2, 100) << endl;
   cout << "Litle is : " << mymin(2.6, 2.4) << endl;
   cout << "Litle is : " << mymin(3.4, 3) << endl;
}
                       

그외에도 비교연산을 제대로 수행하기 위한 형변환이 필요할 것이다.

--------------------------------------------------------------------------------

1.14절. 메모리 할당/해제
메모리 할당과 해제를 위해서 new 와 delete 키워드를 사용할수 있다. 이들은 C 에서 사용하는 malloc, free 대신 사용할수 있다. 만약 배열의 할당을 원한다면 new[] delete[] 를 사용하면 된다. #include <iostream>
#include <cstring>

using namespace std;

int main()
{
   int *d;

   // int 형을 포함할수 있는 새로운 메모리 공간확보하고
   // 주소를 되돌려준다.
   d = new int;
   *d = 21;

   cout << "Type a number : ";
   cin >> *d;
   cout << *d + 5 << endl;

   // 할당받은 메모리 영역을 해제한다.
   delete d;

   // 15개의 int 형자료를 저장할수 있는 새로운 메모리
   // 공간을 확보하고, 주소를 되돌려준다.
   d = new int[15];
   d[0] = 1234;
   d[1] = d[0] + 1234;

   cout << d[0] << ":"<< d[1] << ":" << d[2] << endl;
   delete []d;
   return 0;
}

--------------------------------------------------------------------------------

1.15절. Class
간단히 생각해서 Class 란 발전된 형태의 struct 이다. 데이타와 함께, 데이타를 가공할 METHODS 가 선언될수 있다. 다음은 Class 설명을 위한 간단한 예제이다. #include <iostream>
#include <cstring>

using namespace std;

class vector
{
   public:
       double x;
       double y;

   inline double surface()
   {
       double s;
       s = x*y;
       if (s < 0)
           s = -s;
       return s;
   }
};

int main()
{
   vector a;
   a.x = 3;
   a.y = 4;

   cout << a.surface() << endl;
   return 0;
}
                       

위의 예제코드에서 a를 클래스 vector 의 인스턴스(INSTANCE)라고 한다.


--------------------------------------------------------------------------------

1.16절. 생성자 / 소멸자
만들수 있는 메서드 중에는 생성자(Constructor)와 소멸자 (Destructor), 이것들은 인스턴스가 생성되고 소멸될때 자동적으로 호출되는 메서드이다.

생성자는 인스터스의 여러가지 변수를 초기화하거나, 메모리 할당등의 작업을 위해서 쓰인다. 다음은 오버로드된 2개의 생성자를 이용한 셈플코드이다. #include <iostream>

using namespace std;

class vector
{
   public:
       double x;
       double y;
       vector()
       {
           x = 0;
           y = 0;
       }
       vector(double a, double b)
       {
           x = a;
           y = b;
       }

};

int main()
{
   vector k;
   cout << "vector k: " << k.x << "," << k.y << endl;

   vector m(45, 5);
   cout << "vector m: " << m.x << "," << m.y << endl;

   k = vector (22, 13);
   cout << "vector k: " << k.x << "," << k.y << endl;
}
                       

하지만 이미 앞에서 배운 default parameter 을 사용하면, 번거롭게 overload 하지 않고 코드를 단순화 시킬수 있다. #include <iostream>

using namespace std;

class vector
{
   public:
       double x;
       double y;
       vector(double a = 0, double b = 0)
       {
           x = a;
           y = b;
       }

};

int main()
{
   vector k;
   cout << "vector k: " << k.x << "," << k.y << endl;

   vector m(45, 5);
   cout << "vector m: " << m.x << "," << m.y << endl;

   vector p(5);
   cout << "vector p: " << p.x << "," << p.y << endl;
}

소멸자는 그리 필요하지 않는경우가 많다. 보통은 인스턴스가 제대로 종료되었는지 확인하고, 종료될때 어떤 값을 가지고 종료되는지 알고자하는 목적(DEBUG) 으로 많이 사용된다. 그러나 만약 인스턴스에서 메모리 할당을 했다면 (new 나 malloc 로) 인스턴스를 종료시키기 전에 반드시 메모리를 해제(free) 시켜줘야 한다. 이럴경우 소멸자는 매우 유용하게 사용된다. #include <iostream>

using namespace std;

class person
{
   public:
       char *name;
       int age;

   person(char *n ="no name", int a = 0)
   {
       name = new char[40];
       strncpy(name, n, 40);
       age = a;
   }

   ~person()
   {
       cout << name << " : 40 byte is free : Instance going to be deleted" << e
ndl;
       delete []name;
   }
};

int main()
{
   person me("yundream", 25);
   cout << "name is " << me.name << endl;
   cout << "age is " << me.age << endl;

   person *my;
   my = new person("hello");
   cout << "name is " << my->name << endl;
   cout << "age is " << my->age << endl;
   delete my;
   return 0;
}
                       

(할당된 메모리는 free 를 하거나 프로세스가 종료되지 않는한은 커널에 되돌려지지 않는다.)


--------------------------------------------------------------------------------

1.17절. 클래스 메서드의 선언과 정의 분리
만약 메서드를 inline 으로 작성하고 싶지 않다면, 클래스에는 단지 선언만을 포함하게 유지하고, 메서드의 원형을 별도로 관리하도록 할수 있다. #include <iostream>
using namespace std;

class vector
{
   public:
       double x;
       double y;

       double surface();
};

double vector::surface()
{
   double s= 0;
   for (double i = 0; i < x; i++)
   {
       s = s + y;
   }
   return s;
}

int main()
{
   vector k;

   k.x = 5;
   k.y = 6;
   cout << k.surface() << endl;

   return 0;
}
                       

이렇게 분리할경우 inline 에 비해서 약간의 속도저하가 있을수 있겠지만, 유지/보수가 수월해질것이다.


--------------------------------------------------------------------------------

1.18절. 객체의 배열
당연히 객체를 배열로 선언하는 것도 가능하다. #include <iostream>
#include <cmath>
using namespace std;

class vector
{
   public:
       double x;
       double y;

       vector (double a=0, double b=0)
       {
           x = a;
           y = b;
       }

       double module()
       {
           return sqrt (x*x + y*y);
       }
};

int main()
{
   vector t[3] = {vector(4,5), vector(5,5), vector(2,5)};

   cout << t[0].module() << endl;
   cout << t[1].module() << endl;
   cout << t[2].module() << endl;

   return 0;
}

--------------------------------------------------------------------------------

1.19절. 클래스 멤버변수의 static 선언
클래스 맴버변수는 static 로 선언될수 있으며, static 로 선언되었을경우 모든 인스턴스에서 공유해서 사용할수 있다. 단. static 으로 선언된 변수의 초기화는 클래스의 밖에서만 가능하다. #include <iostream>
#include <cmath>
using namespace std;

class vector
{
   public:
       double x;
       double y;
       static int count;

       vector (double a=0, double b=0)
       {
           x = a;
           y = b;
           count ++;
       }

       ~vector()
       {
           count --;
       }
};

int vector::count = 0;

int main()
{
   cout << "Number of vector : " << endl;
   vector a;
   cout << vector::count << endl;
   vector b;
   cout << vector::count << endl;

   vector *r, *u;

   r = new vector;
   cout << vector::count << endl;
   u = new vector;
   cout << vector::count << endl;

   delete r;
   cout << vector::count << endl;
   delete u;
   cout << vector::count << endl;

   return 0;
}
                       

위의 vector 클래스는 count 라는 static 변수를 가지고 있다. 이 변수는 현재 vector 클래스의 인스턴스의 갯수를 계수하기 위한 용도로 사용된다. vector 클래스의 새로운 인스턴스가 만들어지면 count 를 증가하고 인스턴스가 소멸되면 count 를 감소시킴으로써 인스턴스의 갯수를 유지한다.

--------------------------------------------------------------------------------

1.20절. 클래스 멤버변수의 상수선언
클래스 멤버변수가 static 로 선언되는것과 마찬가지로 상수 (constant)로 선언될수도 있다. 이 변수는 클래스안에서 값이 할당되며, 인스턴스에서 변경될수 없다. 그러나 단지 const 로만 선언했을경우 컴파일러에 따라서 컴파일이 안될수도 있다. 예를들어 gnu 컴파일러의 경우 const static 로 선언해야 될경우가 있다. #include <iostream>
#include <cmath>
using namespace std;

class vector
{
   public:
       double x;
       double y;
       const static double pi = 3.1415927;

       vector (double a=0, double b=0)
       {
           x = a;
           y = b;
       }

       double cilinder_volume()
       {
           return x*x/4*pi*y;
       }
};

int main()
{
   cout << "pi is: " << vector::pi << endl;
   vector k (3,4);
   cout << "Result: " << k.cilinder_volume() << endl;
   return 0;
}

--------------------------------------------------------------------------------

1.21절. this 포인터
클래스에서 각 메서드는 주소에 의한 방식으로 함수를 호출한다. 이렇게 할수 있는 이유는 this 라는 가상의 포인터 때문이다. 클래스에 선언된 모든 메서드는 this 를 명시하지 않더라도 this 가 있는것으로 간주되고 주소에 의해서 함수가 호출된다. 이렇게 하는 이유는 클래스내의 멤버함수를 객체에 의해서 소유하도록 하기 위함이 목적이다. 즉 this 는 보이지 않는 포인터로 객체와 멤버함수를 내부적으로 연결하는 일을 한다. #include <iostream>
#include <cmath>

using namespace std;


class vector
{
   protected:
       double k;
   public :
       double x;
       double y;
       vector(double a= 0, double b= 0)
       {
           x = a;
           y = b;
       }
       double module()
       {
           cout << "module " <<  x << " : " << y<< endl;
           return sqrt(x*x + y*y);
       }

       void set_length(double a = 1)
       {
           double length;
           length = this->module();

           x = x/length *a;
           y = y/length *a;
       }
};


int main()
{
   vector a(3,5);
   cout << "--> " << a.module() << endl;
   a.set_length(2);
   cout << "--> " << a.module() << endl;
   a.set_length();
   cout << "--> " << a.module() << endl;
}

--------------------------------------------------------------------------------

1.22절. 상속
클래스는 다른 클래스로 부터 파생(Derived)될수 있다. 이 새로운 클래스는 원본클래스의 메서드와 변수를 상속 (Inherits) 받게 된다. 이렇게 해서 파생된 클래스는 새로운 메서드와 변수들을 추가함으로써 확장시켜 나갈수 있게 된다.         
#include <iostream>
#include <cmath>
using namespace std;
   
// 원본 클래스
class vector
{
   public:
       double x;
       double y;
       const static double pi = 3.1415927;

       vector (double a=0, double b=0)
       {
           x = a;
           y = b;
       }

       double surface()
       {
           return x * y;
       }
};

// vector 로부터 파생된 새로운 클래스
// 원본 vector 클래스의 표면적을 구하는 작업외에
// 체적을 구하는 작업을 할수있도록 확장되었다.
class trivector: public vector
{
   public :
       double z;

       // trivector 생성자가 호출되기 전에
       // vector 생성자가 호출되어서 m, n 인자를
       // 초기화 한후, 거기에 3차원 지원을 위해서 p 가
       // 초기화 된다.  
       trivector(double m =0, double n =0, double p=0): vector(m,n)
       {
           z = p;
       }

       // 또다른 생성자로 만약에 2차원 정보가
       // 들어왔을경우 3차원으로 변경한다.  
       trivector(vector a, double p = 0)
       {
           x = a.x;
           y = a.y;
           z = p;
       }

       // 3차원 데이타를 이용해서 체적을 구한다.
       // surface()메서드를 호출해서 표면적을 구하고
       // 거기에 높이인 z 를 곱해주면 된다.
       double volume()
       {
           return this->surface() * z;
       }
};

int main()
{
   vector a(4, 5);
   trivector b(1, 2, 3);
   trivector c(a);

   cout << "surface a: " << a.surface() << endl;
   cout << "volume  b: " << b.volume() << endl;
   cout << "surface b: " << b.surface() << endl;
   cout << "volume  c: " << c.volume() << endl;

   trivector d(a,5.8);
   cout << "volume  d: " << d.volume() << endl;
}

--------------------------------------------------------------------------------

1.23절. 다중상속
바로 위에서 상속에 대해서 알아봤는데, C++ 은 1개 이상의 클래스로 부터 상속받는 것도 가능하다. 그러나 다중상속을 이용해서 클래스를 만들경우 나중에 유지/보수가 곤란해지는 문제가 생길수 있음으로, 대체적으로 다중상속은 지양하는 추세이다. #include <iostream>
#include <cmath>
using namespace std;

// 원본 클래스
class vector
{
   public:
       double x;
       double y;
       const static double pi = 3.1415927;

       vector (double a=0, double b=0)
       {
           x = a;
           y = b;
       }

       double surface()
       {
           return x * y;
       }
};

class height
{
   public :
       double z;
       height (double a)
       {
           z = a;
       }

       int is_negative()
       {
           if (z < 0) return 1;
           else       return 0;
       }
};

class trivector: public vector, public height
{
   public :
       trivector(double a= 0, double b=0, double c=0): vector(a,b), height(c)
       {
       }
       double volume()
       {
           return fabs(x* y* z);
       }
};

int main()
{
   trivector a(2, 3, -5);

   cout << a.volume() << endl;
   cout << a.surface() << endl;
   cout << a.is_negative() << endl;
}

--------------------------------------------------------------------------------

1.24절. 캡슐화(은닉)
아마 당신이 C++ 을 처음접해 보았다면, 위의 코드에서 public: 라고 하는 생소한 키워드를 보았을것이다. 이것은 C++ 에서 새로추가된 키워드로 메서드나 멤버변수에 엑세스레벨을 부여하게 된다.

public: 는 프로그램어디에서든지 엑세스 할수 있음을 나타낸다. 이것은 원본클래스와 파생클래스에게 모두 동일하게 적용된다.

private: 는 단지 원본 클래스의 메서드를 통해서만 접근이 가능하다.

protected: private 와 비슷하게 클래스 메서드를 통해서만 접근이 가능하지만, private 와는 달리 원본뿐 아니라 파생된 클레스에서의 접근도 가능하다.

#include <iostream>
#include <cmath>

using namespace std;


class vector
{
   private:
       double x;
       double y;
   public :
       double surface()
       {
           return x * y;
       }
};

int main()
{
   vector b;
   b.x = 2; // 컴파일 에러발생
   b.y = 3; // 컴파일 에러발생
}
                       

위의 경우 c++ 컴파일러로 컴파일할경우 `double vector::x' is private 와 같은 에러메시지를 출력하고 컴파일 중지된다. vector 클래스의 멤버변수 x, y 는 private 로 선언되어 있음으로 단지 현재 클래스의 메서드를 통해서만 접근가능하기 때문이다. 이럴경우 x, y 입력을 위한 전용 메서드를 하나 만들어야 할것이다. #include <iostream>
#include <cmath>

using namespace std;


class vector
{
   private:
       double x;
       double y;
   public :
       double surface()
       {
           return x * y;
       }
       void input(double a, double b)
       {
           x = a;
           y = b;
       }
};

int main()
{
   vector b;
   b.input(11, 40.5);
   cout << b.surface() << endl;
}

--------------------------------------------------------------------------------

1.25절. 가상함수
원본클래스에서 파생된 새로운 클래스는 원본 클래스의 메서드와 멤버변수를 상속받는다는 것을 배워서 알고 있다. 그런데 이런경우를 생각할수 있을것이다. vector 에 module 란 메서드가 있는데, 이 메서드는 다음과 같다. double module()
{
   return sqrt(x*x + y*y);        
}
                       

만약 vector 에서 파생된 trivector 이란 클래스를 선언했다면, trivector 클래스는 vector->module() 를 상속받게 될것이다. 그러나 trivector 의 경우 sqrt 연산을 할때 3차원 데이타를 가지고 연산을 해야 할것이다. double module()
{
       return sqrt(x*x + y*y + z*z);
}
                       

이처럼 메서드를 상속받았을때, 상속받은 메서드의 연산방식이 변경될경우 virtual 로 선언하면 된다. #include <iostream>
#include <cmath>

using namespace std;


class vector
{
   public :
       double x;
       double y;
       virtual double module()
       {
           return sqrt(x*x + y*y);
       }
};

class trivector: public vector
{
   public :
       double z;

   trivector(double m=0, double n=0, double p=0)
   {
       x = m;
       y = n;
       z = p;
   }

   double module()
   {
       return sqrt(x*x + y*y + z*z);
   }
};

int main()
{
   trivector b(2,3,4);
   cout << b.module() << endl;
}

--------------------------------------------------------------------------------

1.26절. 파일스트림 처리
C++ 은 파일처리를 위한 매우 간단한 방법을 제공한다. 다음은 파일을 읽기 위한 코드이다. #include <iostream>
#include <fstream>
using namespace std;

int main()
{
   fstream f;
   char c;

   f.open("seek3.c", ios::in);
   while (! f.eof())
   {
       f.get(c);
       cout << c;
   }

   f.close();

   return 0;
}
                       

다음은 파일에 쓰기 위한 코드이다. #include <iostream>
#include <fstream>
#include <cstdio>
using namespace std;

int main()
{
   fstream f;
   f.open("text.txt", ios::out);

   f << "Hello world " << endl;

   f.close();
   return 0;
}

--------------------------------------------------------------------------------

1.27절. 정형화된 출력
보통 표준 C 언어에서는 printf 를 이용해서 정형화된 출력을 수행한다. C++ 에서는 width() 와 setw()를 이용해서 정형화된 출력을 한다. 이것들은 단지 가장최근의 출력에만 영향을 미친다. #include <iostream>
#include <iomanip>
using namespace std;

int main()
{
   for (int i = 1; i <= 1000; i *=2)
   {
       cout.width(7);
       cout << i << endl;
   }
   for (int i = 0; i <=10 ;i ++)
   {
       cout << setw(3) << i << setw(5) << i * i * i << endl;
   }
   return 0;
}

--------------------------------------------------------------------------------

1.28절. 문자배열을 file 처럼이용하기
좀 이상하게(혹은 쓸모없는 것처럼) 들릴수 있겠지만, 문자배열을 파일처럼 연산하는게 가능하다. 이것은 파일 스트림과 메모리를 연결해서 사용하는 프로그래밍 기법을 가능하도록 해준다. #include <iostream>
#include <cmath>
#include <cstring>
#include <strstream>

using namespace std;

int main()
{
   char a[1024];
   ostrstream b(a, 1024);

   b.seekp(0); // 스트림의 첫번째로 이동
   b << "2+2 = " << 2+2 << ends; // ends 임에 주의
   cout << a << endl;

   double v = 49;
   strcpy(a, "A sinus: ");

   b.seekp(strlen(a));
   b << "sin (" << v << ") = " << sin(v) << ends;
   cout << a << endl;
}
                       

#include <iostream>
#include <cmath>
#include <cstring>
#include <strstream>

using namespace std;

int main()
{
   char a[1024];
   istrstream b(a, 1024);

   strcpy(a, "45.656");
   double k, p;

   b.seekg(0);
   b >> k;

   k = k+1;
   cout << k << endl;

   strcpy(a, "444.23 56.89");
   b.seekg(0);
   b >> k >> p;

   cout << k << ", " << p + 1 << endl;
   return 0;
}

Posted by 창신다이

1. 클래스 생성자의 멤버 초기화는 멤버리스트를 통해서 하는 것이 안전하며 그 순서를 지켜야 한다.

2. 클래스 소멸자는 되도록 virtual로 선언한다. 이 클래스를 상속한 클래스가 있을 경우 virtual이 아닌 소멸자는 호출되지 않기 때문에 메모리 leak이 생긴다.

3. 클래스 생성자 함수에서 자식 클래스가 만드는 pure virtual function을 부르는 일이 없도록 한다. 치명적 오류의 원인.

자세한 것은 http://sparcs.kaist.ac.kr/~ari/each/article.each.605.html 에서 순서대로 '다음글' 링크를 따라 보면 된다.

원래 따라갔던 링크는 http://codian.net/blog/archive/0408211736330952_M_2005_02.html#050211110151TKJG 이다.

Posted by 창신다이

#include <stdio.h>
#include <locale.h>

void main()
{
wchar_t a = L'한';
setlocale(LC_ALL, "Korean");
wprintf(L"%c");
}

//////////////////////////////////

#include <stdio.h>
#include <locale.h>

void main()
{
wchar_t *a = L"한글처리";
setlocale(LC_ALL, "Korean");   //한글로 인코딩
wscanf(L"%s", a);
wprintf(L"%s", a);
}

Posted by 창신다이

데이타를 대표하는 클래스 하나,
각각의 뷰어의 기능을 가지는 각각의 뷰어 클래스.
단, 데이타 클래스는 내부 데이타 수정의 모든 기능을 가지면서 외부에서 직접 변수를 수정 못하게 해야함.

Posted by 창신다이

1. 연결상태를 어떻게 체크하는가?
- 일단, 소켓통신에는 크게 TCP 방식과 UDP 방식이 있습니다. TCP 방식과 UDP 방식의 가장 큰
차이점은 TCP는 \'연결\'을 한다는 것이고, UDP는 \'연결\'을 하지 않는다는 것입니다.
따라서, 연결상태를 체크한다는 것은 당연히 TCP 방식을 사용할 경우의 이야기이겠지요.
그렇다면, TCP 방식으로 소켓통신을 할 때 \'연결상태\'를 어떻게 체크할까요?
바로 \'3-Way Handshaking\' 기법을 사용합니다. 3-Way Handshaking이 무엇이냐면,
두 PC는 통신을 하기 전에 서로 \'통신 시작한다\'라는 신호를 주고 받는데, 이것이 3단계로
이루어집니다.

1단계: A PC에서 B PC로 SYN 패킷을 보낸다.(나 너랑 통신할래~)
2단계: B PC가 이 SYN 패킷을 받아서 A PC에게 ACK 패킷을 보낸다.(알았어 통신하자~)
3단계: A PC가 이 ACK 패킷을 받아서 다시 B PC에게 ACK 패킷을 보낸다.(그래 이제 간다~)

이 3단계가 완료되면 \'연결상태\'가 되며, 연결이 끊어지기 전까지는 쭈욱 연결상태가 유지됩니다.
연결이 끊어지는 경우는 2가지가 있는데, 하나는 통신을 완료한 후 연결을 종료하는 것이고,
다른 하나는 임의의 장애(?)가 발생하여 강제로 종료되는 것입니다.
통신 완료 후 연결 종료는 연결을 종료하려는 PC가 상대 PC에게 FIN 패킷을 보냄으로써 이루어집니다.
그러나, 장애로 인하여 연결이 종료되는 경우도 있는데, 이 경우 한 PC가 일정 시간 이상 다른 PC의
신호에 응답하지 않으면 연결이 강제로 종료됩니다. 그리고 이때 사용되는 신호란 특별한 것이 아니라,
서로 데이터를 주고 받다가 일정 시간 이상 데이터가 안오면 데이터를 못받은 PC가 \

Posted by 창신다이

Here is an extended example of the console mode OLEDB program that has Insert/Update/Delete functions:

//file: olsamp.cpp
//auth: dick warg
//date: 3/30/2000
//func: minimal oledb program

#include <atldbcli.h>
#include <iostream>

using namespace std;

// define a class for the ACCESSOR to hold the data from the table
class myNwCust
{
public:
   // data elements
   char m_CustomerID[6];
   char m_CompanyName[41];
   char m_ContactName[31];
   char m_Phone[25];


   // column binding  -- I only want these 4 fields (see MS documentation
   // for examples of Multiple Accessor)

   BEGIN_ACCESSOR_MAP(myNwCust,2)
       BEGIN_ACCESSOR(0,true)
           COLUMN_ENTRY_TYPE(1,DBTYPE_STR, m_CustomerID)
           COLUMN_ENTRY_TYPE(2,DBTYPE_STR, m_CompanyName)
           COLUMN_ENTRY_TYPE(3,DBTYPE_STR, m_ContactName)
           COLUMN_ENTRY_TYPE(10,DBTYPE_STR, m_Phone)
       END_ACCESSOR()
       BEGIN_ACCESSOR(1,false)
           COLUMN_ENTRY_TYPE(3,DBTYPE_STR, m_ContactName)
       END_ACCESSOR()
   END_ACCESSOR_MAP()
};


void my_insert(CCommand <CAccessor<myNwCust> >& cust);
void my_update(CCommand <CAccessor<myNwCust> >& cust);
void my_delete(CCommand <CAccessor<myNwCust> >& cust);
bool my_find(CSession& session, CDBPropSet* propset, CCommand <CAccessor<myNwCust> >& cust);


int main()
{

try{
   // fire up COM
   HRESULT hr = CoInitialize(0);
   if(FAILED(hr))
   {
       cout << "Can't start COM!? " << endl;
       return -1;
   }

   // do all the work inside here so the destructors get called before
   // co-uninitialize
   {
           // declare the OLEDB objects INSIDE a block so they will be destroyed before
       // CoUnitialize is called
       CDataSource ds;
       CSession    session;
       CCommand <CAccessor<myNwCust> > cust;
       CDBPropSet propset(DBPROPSET_ROWSET);

   // connect to the database
       hr = ds.Open(_T("MSDASQL"), "OLE_DB_NWind_Jet", "sa", "");
       if(FAILED(hr))
       {
           cout << "Can't open Nwind" << endl;
           return -1;
       }

       /* *************************************************************************
          The CDBPropSet controls the way the database gets opened
       
          The documentation for all these properties can be found if you look in
          the MSDN Help reference:
          \Platform SDK\Database and Messaging Services\Microsoft Data Access SDK\
          OLEDB Programmer's Reference\Part 3 Appendixes\Appendix C\Properties Table

           IF YOU DON'T SET THESE PROPERTIES YOU WON'T BE ABLE TO SCROLL THE TABLE OR MAKE
           CHANGES TO IT!!

           In addition the table MUST have a Primary Key defined.
           No primary key = NO INSERT, NO UPDATE  & NO DELETE

           If you use an automatic integer (identity column) in your table it must not be
           in the Accessor that is used to INSERT to the table. This means that you and I must
           use Multiple Accessors if there is an identity column for the table.
       ******************************************************************************/

       propset.AddProperty(DBPROP_CANFETCHBACKWARDS,   true);
       propset.AddProperty(DBPROP_IRowsetScroll, true);
       propset.AddProperty(DBPROP_IRowsetChange, true);
       propset.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT |
           DBPROPVAL_UP_DELETE );

       // start the session
       hr = session.Open(ds);
       if(FAILED(hr))
       {
           cout << "Can't open Nwind SESSION" << endl;
           ds.Close();
           return -1;
       }

       // construct the query string
       char mySQL[] = "SELECT * FROM Customers ";


       // open the dataset
       hr = cust.Open(session, mySQL, &propset) ;

   /*  use this form of open without a property set
       if you only need to read the table

       hr = cust.Open(session, mySQL) ; // <---- read only
   */
       if(FAILED(hr))
       {
           cout << "Can't open Nwind TABLE" << endl;
           session.Close();
           ds.Close();
           return -1;
       }

       int line = 0;

       // read all the data
       while(cust.MoveNext() == S_OK)
       {
           char buff[81];
           sprintf(buff,"%d %-5s %-35s %-20s %-15s",++line, cust.m_CustomerID,
                               cust.m_CompanyName,
                               cust.m_ContactName ,
                               cust.m_Phone);
          
           cout << buff << endl;
       }

       // process some user interactions

       char ans[10] ;
       ans[0] = '\0';

       while (ans[0] != 'q')
       {
           cout << "What action? f)ind, i)nsert, d)elete, u)pdate, q)uit ";
           cin.getline(ans, sizeof(ans));
           switch(ans[0])
           {
           case 'i':
               my_insert(cust);
               break;
           case 'd':
               // you need to find a record before you can delete it
               if(my_find(session, &propset, cust))
                   my_delete(cust);
               break;
           case 'u':
               // you need to use find before you update too
               if(my_find(session, &propset, cust))
                   my_update(cust);
               break;
           case 'f':
               my_find(session, &propset, cust);
               break;
           }
       }


       cust.Close();
       session.Close();
       ds.Close();

   }// the destructors get called  before the CoUninitialize
   cout << "That's All Folks" << endl;
   CoUninitialize();

   return 1;
}
catch(...)
{
   cout << "Unknown failure" << endl;
   return -1;
}
}


////////////////////////////// functions //////////////////////////////////////
void my_insert(CCommand <CAccessor<myNwCust> >& cust)
{
   char buff[200];


   cout << "Insert Customer ID  ";
   cin.getline(buff, sizeof(buff));
   strcpy((char*)cust.m_CustomerID, buff);

       cout << "Enter Company Name  ";
   cin.getline(buff, sizeof(buff));
   strcpy((char*)cust.m_CompanyName, buff);

   cout << "Enter Contact Name  ";
   cin.getline(buff, sizeof(buff));
   strcpy((char*)cust.m_ContactName, buff);

   cout << "Enter Phone  ";
   cin.getline(buff, sizeof(buff));
   strcpy((char*)cust.m_Phone, buff);

   HRESULT hr = cust.Insert(0);  // <----- This is where we add the new record
   if(hr == S_OK)
   {
       cout << "INSERT OK \n";
   }
   else
   {
       cout << "INSERT FAILED\n";
   }


}

void my_update( CCommand <CAccessor<myNwCust> >& cust)
{
   /* this is a simple minded update that only changes the contact name
      but you get the idea */

   char buff[100];


   cout << "Update Contact Name\n";
   cin.getline(buff, sizeof(buff));
  
   strcpy((char*)cust.m_ContactName, buff);

   cout << cust.m_CustomerID << endl;
   cout << cust.m_CompanyName << endl;
   cout << cust.m_ContactName << endl;
   cout << cust.m_Phone << endl;

   /* update the record. 
  
     The SetData() method actually does the update. The Update() Method
     kinda flushes the changed data to the database, we don't need that for
     this simple example. 
   */
   HRESULT hr = cust.SetData(1);
   if (FAILED(hr))
   {
       cout << "UPDATE FAILED\n";
   }
   else
   {
       cout << "UPDATE OK\n";
   }
}

void my_delete( CCommand <CAccessor<myNwCust> >& cust)
{
   cout << "Delete ? \n";
   char ans[10];

   cout << cust.m_CustomerID << endl;
   cout << cust.m_CompanyName << endl;
   cout << cust.m_ContactName << endl;
   cout << cust.m_Phone << endl;
  
   HRESULT hr;


   cin.getline(ans,sizeof(ans));
   if (ans[0] == 'y')
       hr = cust.Delete();
   else
       return;


   if (FAILED(hr))
   {
       cout << "DELETE FAILED\n";
   }
   else
   {
       cout << "DELETE OK\n";
   }  

}

bool my_find(CSession& session, CDBPropSet* p_propset, CCommand <CAccessor<myNwCust> >& cust)
{
   char custid[10];
   char SQL[200];

   cout << "Enter customer id ";
   cin.getline(custid, sizeof(custid));

   strupr(custid);  // upper case for compare

  
   sprintf(SQL,"SELECT * FROM Customers WHERE CustomerID = '%s'", custid);

   cust.Close();

   HRESULT hr = cust.Open(session, SQL, p_propset);
   if(FAILED(hr))
   {
       cout << "Can't open find that customer\n";
       cout << SQL << endl;
       return false;
   }

  
   hr = cust.MoveFirst();


   if(FAILED(hr))
   {
       cout << "Can't move to that customer\n";
       return false;
   }


   cout << cust.m_CustomerID << endl;
   cout << cust.m_CompanyName << endl;
   cout << cust.m_ContactName << endl;
   cout << cust.m_Phone << endl;
   return true;
}

Posted by 창신다이

GET / HTTP/1.1
Accept: */*
Accept-Language: ko
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Host: www.XXXXXX.com
Connection: Keep-Alive
기타해더: 등...
Cookie: 등... \r\n\r\n

이런식으로 만들어서 그냥 소켓으로 보낸다
필요한게 있으면 추가.

www.XXXXXXX.com:80 포트로 접속.

POST 는 \r\n 한번 한 다음에 헤더에서 \r\n 다음에 q=test1&p=test2    \r\n\r\n
이런식으로 규격만 지키면 된다.

CSocket sock;
sock.Create();
sock.connect("서버주소",80);
sock.Send(헤더내용, 헤더길이);
헤더는 문자열 버퍼(char szBuff[])에 저장.

get은 그냥 보내면 되고,
post 는 보통 헤더 한번 Send로 보내고 post 값 한번 더 보내는 2번으로 보낸다.

무조건 http 통신의 끝은 \r\n\r\n 이여야함(엔터두번)

단 HTTP/1.1 규약인 경우만, 즉 get / 는 엔터 한번으로 통신 끝

get / HTTP/1.1 로 시작하면 엔터 두번으로 끝냄

Posted by 창신다이

>jar %1 %2

첫번째 인자 %1
두번째 인자 %2

...

Posted by 창신다이

원문: http://blog.naver.com/woorara7/20017399440

/////////////////////////////////////////////////////////////////////
//  char -> wchar

wchar_t* CharToWChar(const char* pstrSrc)
{
   ASSERT(pstrSrc);
   int nLen = strlen(pstrSrc)+1;

   wchar_t* pwstr      = (LPWSTR) malloc ( sizeof( wchar_t )* nLen);
   mbstowcs(pwstr, pstrSrc, nLen);

   return pwstr;
}

/////////////////////////////////////////////////////////////////////
// wchar -> char
char* WCharToChar(const wchar_t* pwstrSrc)
{
   ASSERT(pwstrSrc);

#if !defined _DEBUG
   int len = 0;
   len = (wcslen(pwstrSrc) + 1)*2;
   char* pstr      = (char*) malloc ( sizeof( char) * len);

   WideCharToMultiByte( 949, 0, pwstrSrc, -1, pstr, len, NULL, NULL);
#else

   int nLen = wcslen(pwstrSrc);

   char* pstr      = (char*) malloc ( sizeof( char) * nLen + 1);
   wcstombs(pstr, pwstrSrc, nLen+1);
#endif

   return pstr;
}

Posted by 창신다이

예를 들어, 다음과 같이 동적으로 할당한 num이라는 변수가 있다면,
int * num = new int[100];

처음부터 100개까지의 항목을 보고 싶다면(전체),
Watch 창에서
num, 100
그러면 watch 창에 num[0]부터 num[99]까지가 표시.

만약 10번째 항목부터 90개의 항목을 표시하고 싶다면,
(num+10), 90

Posted by 창신다이

BLOG main image
오랫동안 꿈을 그리는 사람은 마침내 그 꿈을 닮아 간다. -앙드레 말로- by 창신다이

공지사항

카테고리

분류 전체보기 (248)
공장이야기 (115)
Education (30)
회사이야기 (19)
일상 (73)

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

Total :
Today : Yesterday :