선언

CString str;

time_t Itime;

struct tm *cur;

time(&Itime);

cur = localtime(&Itime);  // 현재시간을 얻음


사용

str.Format(_T("[%04d/%02d/%02d %02d:%02d:%02d]"),

                     cur->tm_year+1900, cur->tm_mon + 1, cur->tm_mday, cur->tm_hour, cur->tm_min, cur->tm_sec);

                  


출력

2017/04/21 06:21:33

'Study Note > Programming' 카테고리의 다른 글

[MFC] 정적인 그래프 그리기.  (0) 2017.02.07
[OpenCV]OpenCV를 이용해 영상 출력  (2) 2017.01.09
[OpenCV] 이미지 출력하기.  (0) 2017.01.06
[OpenCV] 설치 및 설정 (VS)  (0) 2017.01.06
[MFC] assert() 함수  (1) 2016.11.22

정적 그래프를 처음해보기때문에 차근차근 진행해보도록 하겠다.


직접그려볼까 객체들을 찾아보다가 인터넷에 제공되는 API를 발견하였다.


 http://blog.tcltk.co.kr/?p=962 사이트에서

Chart Director를 알게되었다.


ChartDirector 홈페이지

  http://www.advsofteng.com/index.html


해당 홈페이지로 접속하셔서 Chart Demo 및 문서를 다운 받을 수 있다.

32bit 자료를 다운 받았다.


다운 받은 파일을 압축해제하면 아래와 같이 폴더 구성을 하고 있다.

 [cppdemo] : c++로 제작 된 chart 예제

 [doc] : 라이브러리 사용법이 들어있는 설명서

 [include] : Chart를 사용하기 위한 라이브러리 소스코드

 [lib] : 컴파일을 하기 위한 lib 파일과 실행을 위한 chartdir60.dll 파일이 포함되어 있습니다.

 [mfcdemo] : mfc로 제작 된 chart 예제

 [qtdemo] :  qt로 제작 된 chart 예제


여기서 사용하기위한 [include] 와 [lib] 폴더를 사용할 프로젝트 폴더에 복사한다.

또 mfcdemo/mfcdemo/폴더에 있는 ChartViewer의 .cpp .h 파일도 프로젝트 폴더에 복사한다.


[프로젝트 속성] - C/C++ 에서 라이브러리 폴더를 추가해주고

Link 탭에서 chairtdir60.lib 를 추가해준다.


PicControl을 추가해주고 type을 Bitmap으로 변경해 준다.

이후 변수 추가는 CChartViewer m_ChartView로 추가 해주었다.


dlg.h 에 ChartViewer.h를 Include해주고

dlg.cpp 에 아래 코드를 추가 해준다.

//OnInitDialog() 에 추가해야할 소스코드

// TODO: Add extra initialization here

// 차트에 필요한 데이터

    double data0[] = {42, 49, 33, 38, 51, 46, 29, 41, 44, 57, 59, 52, 37, 34, 51, 56,

        56, 60, 70, 76, 63, 67, 75, 64, 51};

    double data1[] = {50, 55, 47, 34, 42, 49, 63, 62, 73, 59, 56, 50, 64, 60, 67, 67,

        58, 59, 73, 77, 84, 82, 80, 84, 89};

    double data2[] = {87, 89, 85, 66, 53, 39, 24, 21, 37, 56, 37, 22, 21, 33, 13, 17,

        4, 23, 16, 25, 9, 10, 5, 7, 6};

    const char *labels[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",

        "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23",

        "24"};


    // Create a XYChart object of size 350 x 230 pixels

    XYChart *c = new XYChart(350, 230); //차트의 전체 크기를 정한다


    // Set the plotarea at (50, 30) and of size 250 x 150 pixels.

    c->setPlotArea(50, 30, 250, 150); //차트위 위치와 높이 넓이를 정한다.


    // Add a legend box at (55, 0) (top of the chart) using 8 pts Arial Font. Set

    // background and border to Transparent.

    c->addLegend(55, 0, false, "", 8)->setBackground(Chart::Transparent);


    // Add a title to the x axis

    c->xAxis()->setTitle("Network Load for Jun 12");


    // Add a title to the y axis

    c->yAxis()->setTitle("MBytes");


    // Set the labels on the x axis.

    c->xAxis()->setLabels(StringArray(labels, (int)(sizeof(labels) / sizeof(labels[0]))));


    // Display 1 out of 2 labels on the x-axis. Show minor ticks for remaining

    // labels.

    c->xAxis()->setLabelStep(2, 1);


    // Add three area layers, each representing one data set. The areas are drawn in

    // semi-transparent colors.

    c->addAreaLayer(DoubleArray(data2, (int)(sizeof(data2) / sizeof(data2[0]))),

        0x808080ff, "Server #1", 3);

    c->addAreaLayer(DoubleArray(data0, (int)(sizeof(data0) / sizeof(data0[0]))),

        0x80ff0000, "Server #2", 3);

    c->addAreaLayer(DoubleArray(data1, (int)(sizeof(data1) / sizeof(data1[0]))),

        0x8000ff00, "Server #3", 3);

m_chartView.setChart(c);  //m_chartView에 Chart를 보여주기 위한 코드



하... vs2013에 버그가 존재한다. 

Visual Studio 2013 버그 - error RC2108: expected numerical dialog constant ) 구글링을 해보니

 

첫 번째로, 임시 조치 방법으로는 아래와 같이 수동으로 코드를 바꿀 수 있습니다.

 

변경 전 (오류 발생)

 CONTROL IDB_BITMAP1,IDC_STATIC,2,2,89,82,NOT WS_GROUP

변경 후

CONTROL IDB_BITMAP1, IDC_STATIC, "Static", SS_BITMAP, 2, 2, 89, 82, NOT WS_GROUP

 

두 번째로, Visual Studio 2013 Update 버전을 설치하면 됩니다.

라고 한다. 번거롭다.. 다시 이런 버그를 만나지 않기위해 차 후 업데이트를 해야겠다.



결과적으로


성공할 수 있다.


'Study Note > Programming' 카테고리의 다른 글

[C++] time함수와 tm구조체 사용법  (0) 2017.04.21
[OpenCV]OpenCV를 이용해 영상 출력  (2) 2017.01.09
[OpenCV] 이미지 출력하기.  (0) 2017.01.06
[OpenCV] 설치 및 설정 (VS)  (0) 2017.01.06
[MFC] assert() 함수  (1) 2016.11.22

OpenCV를 이용하여 동영상 파일 출력하기.

작업환경 – OS : window8.1K , Tool : VisualStudio 2010 , OpenCV Ver : 2.4.11 )

 

(앞서 했던 설정을 기본으로한다.)

 

테스트에 앞서 프로젝트 폴더 내 테스트할 영상을 이동시켜둔다.

 

영상 출력이라고해서 어려워보이지만 OpenCV에서 기본 함수를 제공하므로 비교적 간단하다.

이미지 출력과 차이점은 이미지는 한장의 사진이라면 동영상은 여러장의 사진을 연속적으로 출력하는 것이라 볼 수 있다.

 

#include <opencv\highgui.h>

 

int main()

{

        IplImage *frame;

        CvCapture *capture = cvCaptureFromAVI("test.MOV"); // 영상파일을 로드

        cvNamedWindow("Test",0); // Window창을 생성

 

        while(capture) { // capture 영상이 로드 되었다면 출력

               frame = cvQueryFrame(capture); // 영상을 프레임에 넣음  

               cvShowImage("Test",frame);     // 영상을 띄움

 

               if(cvWaitKey(1)==27){          // ESC(27)  누르면 탈출

                       cvReleaseCapture(&capture);

                       break;

               }

        }

        cvDestroyWindow("Test");

        return 0;

}

 

 

 

CvCapture형식의 capture에 영상을 저장한다.

동영상 파일을 불러올 때는

cvCaptureFromFile() 이나

cvCreateFileCapture() 또는  

cvCaptureFromAVI()중 하나를 선택하여 사용한다.

(인자로는 파일이름파일형식을 넣어준다).

파일 형식은 avi, wmv, mp4, 3gp, mkv, mov 등등이 사용 가능하다.


* PC에 달린 캠 영상을 출력하기위해서는

- cvCreateFromCAM(int index) 를 사용하면 된다.

Index 값으론 사용할 카메라를 지정한다. 카메라가 1개인 경우 혹은 여러 개 중에서 특정한 카메라를 지정하지 않을 경우는 -1을 사용한다. 만약 2개인 경우 index값이 0이면 카메라를 선택할 수 있는 창이 나타난다.


 

cvQueryFrame()함수는 동영상 혹은 카메라로부터 프레임을 읽고 반환하는 함수이다.

 IplImage* cvQueryFrame( CvCaptuer* capture );

 

결과


사진으로 보이지만 영상파일이고 제대로 동작함을 확인할 수 있다.

'Study Note > Programming' 카테고리의 다른 글

[C++] time함수와 tm구조체 사용법  (0) 2017.04.21
[MFC] 정적인 그래프 그리기.  (0) 2017.02.07
[OpenCV] 이미지 출력하기.  (0) 2017.01.06
[OpenCV] 설치 및 설정 (VS)  (0) 2017.01.06
[MFC] assert() 함수  (1) 2016.11.22

(환경 - OS : Window8.1K, Tool : Visual Studio 2010, OpenCV ver : 2.4.11)


OpenCV를 이용하여 이미지 출력하기.

앞서 했던 설정을 기본으로한다.

 

먼저 이미지를 준비한 뒤, 저장하고 프로젝트 폴더로 이동시킨다.

 

아래와 같은 코드를 작성을 하면

#include <opencv2\core\core.hpp>

#include <opencv2\highgui\highgui.hpp>

using namespace cv;

 

void main() {

 

        Mat image = imread("Lenna.png"); // disk에서 그림을 불러온다

        if(!image.data) exit(1); // 이미지가 있는지 확인하고 없으면 종료

 

        imshow("Lenna",image); // 이미지를 보여주는 함수. Par(1) 이름

       

        waitKey(0); //Wait for keystroke

}

 

아래와 같은 결과물이 도출된다.




* OpenCV 함수를 참고하여 만들어 보았다.

#include <opencv\highgui.h>


int main() {

IplImage *capture = cvLoadImage("Lenna.png");

cvNamedWindow("Lenna",1);

cvShowImage("Lenna",capture);

cvWaitKey(0);


// cvReleaseImage(&capture);

// cvDestroyWindow("Lenna");


return 0;

}

 


cvLoadImage()함수는 영상 데이터의 구조체 포인터를 반환한다. 인자 값으로 파일명과 형식을 넣어준다.

구조체의 이름은 IplImage이며, 단일 채널, 다중 채널, 정수형, 실수형 등 모든 형태의 영상 데이터를 IplImage로 표현할 수 있다. 또한 BMP, DIB, JPEG, JPE, PNG, PBM, PGM, PPM, SR, RAS, TIFF 등의 영상 포맷을 지원한다.

*출력할 영상은 프로젝트 폴더내에 존재하여야 한다.


cvNamedWindow()는 영상을 표시할 윈도우를 하나 만드는 일을 한다.

- 첫 번째 인자는 윈도우의 이름으로 등록된다.

- 두 번째 인자는 윈도우의 속성을 지정한다. 여기에는 0(기본값) 또는 1이 들어갈 수가 있다.

인자값이 0으로 지정되면 불러오는 영상의 크기에 상관없이 윈도우 크기는 일정하게 고정이 되고, 영상이 윈도우의 크기에 맞게 확대 또는 축소되어 나타난다. 만약 1(CV_WINDOW_AUTOSIZE)이면 불러오는 영상의 실제 크기에 맞게 윈도우의 크기가 자동으로 조절된다.


cvShowImage()함수는 IplImage* 타입으로 생성된 영상을 해당 제목을 갖은 윈도우에 영상을 출력한다.

- 첫번째 인자는 윈도우의 이름이고,

- 두번째 인자는 IplImage이다.


cvWaitKey()함수는 프로그램의 동작을 잠시 멈추고 사용자로부터 키 입력을 기다린다.

양의 정수일 경우 밀리초(millisecond) 단위로 지정한 시간동안 대기한다.

인자값이 0이나 음수일 경우 키가 눌려질 때 까지 무한정 기다린다.


cvReleaseImage()함수는 할당된 메모리 공간을 해제한다. 

인자로 IplImage*의 주소값을 전달해준다. 이 함수가 실행된 후 해당 IplImage는 NULL로 설정된다.


cvDestroyWindow()함수는 윈도우를 닫고, 윈도우를 위해 동적할당된 메모리 공간을 모두 해제한다. 


cvDestroyAllWindows()함수를 이용하여 한번에 모든 창을 닫을 수도 있다.


***** 간단한 프로그램의 경우 프로그램이 종료할 때 운영체제에 의해 할당된 모든 리소스들이 자동으로 반환되지만 cvReleaseImage()함수와 cvDestroyWindow()함수를 직접 호출하여 리소스를 반환하는것이 좋다.



'Study Note > Programming' 카테고리의 다른 글

[MFC] 정적인 그래프 그리기.  (0) 2017.02.07
[OpenCV]OpenCV를 이용해 영상 출력  (2) 2017.01.09
[OpenCV] 설치 및 설정 (VS)  (0) 2017.01.06
[MFC] assert() 함수  (1) 2016.11.22
메모리 관리 문제  (1) 2016.11.22

(환경 - OS : Window 8.1K , Tool : Visual Studio 2010, OpenCV Ver : 2.4.11)


OpenCV 입문

 

1. OpenCV 설치

- OpenCV 홈페이지(http://opencv.org/download.html)에서 OpenCV 최신 버전을 다운로드한다.

 

- 제어판 - 시스템(윈도우키 + Pause)에서 환경변수 설정을 한다. 시스템 변수에서 새로 만들기를 클릭한다.


 


 

2. Visual Studio 설정

l  C/C++ 목록이 없다면 아무거나 컴파일 하면 생성됨





 

솔루션 플랫폼을 x64로 변경해주는데 없다면 구성관리자 탭에 들어간 후,


새로만들기로 추가해주면 된다.


opencv_calib3d2411d.lib

opencv_contrib2411d.lib

opencv_core2411d.lib

opencv_features2d2411d.lib

opencv_flann2411d.lib

opencv_gpu2411d.lib

opencv_highgui2411d.lib

opencv_imgproc2411d.lib

opencv_legacy2411d.lib

opencv_ml2411d.lib

opencv_nonfree2411d.lib

opencv_objdetect2411d.lib

opencv_ocl2411d.lib

opencv_photo2411d.lib

opencv_stitching2411d.lib

opencv_superres2411d.lib

opencv_ts2411d.lib

opencv_video2411d.lib

opencv_videostab2411d.lib



프로젝트 폴더 안에 jpg파일을 넣고 실행하면

#include <opencv\cv.h>

#include <opencv\highgui.h>

 

int main()

{

        IplImage *image = cvLoadImage("opencv.jpg");

        cvShowImage("Test Image", image);

        cvWaitKey(0);

        cvReleaseImage(&image);

        return 0;

}

 

 

 

이와 같은 결과를 얻을 수 있다.

'Study Note > Programming' 카테고리의 다른 글

[OpenCV]OpenCV를 이용해 영상 출력  (2) 2017.01.09
[OpenCV] 이미지 출력하기.  (0) 2017.01.06
[MFC] assert() 함수  (1) 2016.11.22
메모리 관리 문제  (1) 2016.11.22
[MFC] 대화상자 Domodal, Modaless  (0) 2016.11.19

졸업작품을 준비할 때 썼던 assert 함수에 대해 기록하고자한다.


assert 함수는 assert.h 헤더를 추가해 주어야 사용 할 수 있다고 인터넷 설명에 나와있지만


기본적인 사용 (예로 설명하겠다.) 을 하고자 한다면 assert.h없이 그냥 사용하여도 무방하다고 한다.


assert는 조건에 따라 에러메세지를 띄우고 종료되므로 어떠한 가정하에 점검하기 좋은 방법이다. (Debug 모드에서만)

 -> Release 모드에서는 코딩하지 않음.



원리는 간단하다.


assert(parm) 인데 파라미터 값이 1이 된다면 에러없이 코딩 될 것이고

                                          0이 된다면 에러로 코딩이 종료될 것이다.

( 조건문을 떠올리면 이해하기 쉽다. )

--> 그렇다면 어디서 Err난지도모르고 쓸모 없지 않는가 싶다.


어디서 에러난지 구분하기위해 메세지를 넣어야겠다.


a=1;

assert(a!=1 && "a는 1이지");

//assert의 인자값은 거짓(FALSE) 이므로 "a는 1이지"란 메세지를 띄우며 종료 된다.




정리하자면

- assert 매크로는 코드상 과정을 철저하게 점검하기 위해 간단히 사용 할 수 있다.

- 프로그램을 방어적으로 만들어줌.

- Release 모드시 assert 매크로는 컴파일되지 않는다 => 코드완료 후 일일이 안지워도 됨)

여기서 주의할점은

 *** Release 모드일때는 컴파일 되지 않기 때문에 사용되는 데이터는 변경해서는 안된다.



  


메모리 누수에 대해 알아보다가 좋은 글이 있어 담아왔습니다.

(URL) http://powergi.tistory.com/entry/embedded%EC%97%90%EC%84%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B4%80%EB%A6%AC

댓글에도 많은 의견이 있으므로 참고하면 좋겠습니다.

==================================================================

1. 개요

이 문서는 ESP-NS에서 동작하는 응용 프로그램을 
작성할때 메모리 할당과 해제및 메모리 처리에 
대한 주의점을 소개합니다. 

작성자 : 유영창 frog@falinux.com
작성일 : 2004년 9월 17일 
수정일 : 

관련된 ADK( Application Developer Kit ) 디렉토리 

adk/sample/check_index
adk/sample/assert


2. 임베디드에서 메모리 관련 문제 

임베디드 시스템은 사용시간에 따라서 크게 두가지로 
나누어 볼수 있읍니다. 

첫번째는 필요한 경우만 전원을 넣고 동작시켜 사용하는 경우로 
동작 시간이 짧은 경우입니다. (참으로 고마운 시스템입니다.)

두번째는 모니터링 시스템같이 지속적인 제어가 필요하여 
1년 365일 전원이 절대로 나가면 안되는 경우 입니다. 

프로그래머 입장에서 보면 첫번째 방식을 좋아 하게 됩니다. 
이건 무정전 시스템에 사용되는 프로그램을 작성하신분들이라면
온몸으로 느끼는 감정입니다. ( 해본 사람들은 압니다. ㅜㅜ )


시스템이 무정전으로 동작한다는 것은 여러가지를 고려 해야 합니다.
그중 으뜸은 메모리 누수 입니다. 

C 로 작성하는 프로그램은 반드시 메모리에 관련된 문제 때문에 
한번 이상은 반드시 고생하게 됩니다. 

더구나 C 언어에 익숙하지 않으신 분이라면 포인터 참조에 관련된
수 많은 버그로 엄..청..난... 고생을 합니다. 

그래도 

납품하기전에 메모리 관련된 버그 문제점을 알게 되면 그나마 
다행입니다.

그러나 프로그래머 입장에서 두고 두고 속썩이는 것중 하나가 
장기간 동작하다 멈추는 경우입니다.

프로그램을 수정해서 버그를 잡았는지 확인하려고 하면 
몇일씩이나 걸리기 때문에 프로그래머들을 미치기 일보 
직전까지 만듭니다. ( 대부분의 경우 어디에서 발생했는지도 
잘 모르죠.. )

이런 경험을 여러번 하다보면 나름대로의 방법론이 생깁니다.

이런 경험과 관련되어 메모리를 다루는 방법에 대한 몇(?)가지와
메모리 할당과 해제에 관련된 함수를 소개하려고 합니다. 


3. 배열을 사용하라....

PC 프로그램을 작성하시던 분들이 임베디드 시스템에서
프로그램을 작성할때 가장 걱정되는 습관 중 하나가 
메모리 할당과 해제를 아주 좋아 한다는 겁니다. 

PC 시스템에서 작성하는 프로그램은 실장된 메모리가 
많기 때문에 메모리 할당과 해제를 이용하면 
유연한 프로그램이 가능해 집니다. 

그..러..나..

임베디드에는 메모리 할당과 해제를 자주 이용하는 습관은
절대적으로 말리고 싶은 것 습관중 하나입니다. 

보통 제품을 설계하는 분들이 개발자들에게 요구하는 것중 
하나가 만능제품이죠...

그런데 이 만능은 프로그래머가 만능이 되어야 합니다.
이런 경우에도 적용될수 있고 저런 경우에도 적용될수 있고 

마음약한 개발자들은 이런 요구를 수용합니다.

그러다 보니 개발해야 하는 프로그램 구조가 요구 사항에 
가변적인 구조를 가지게 되죠..

결국 메모리 할당 구조와 리스트와 같은 자료 구조를 사용하게
됩니다. 

이때부터 개발자는 머리털 빠지기 시작합니다. 
( 제가 속빈 인간이 된 사연이 여기에 있읍니다. )
리스트구조와 메모리 할당은 시스템의 버그 원인 순위에 
가장 상위 순위를 차지 합니다. 

오랜 연륜을 가지는 개발자들은 일단 이런 영업 요구에 
적절히 대항합니다. 

그리고 어느정도 제품이 필요한 요구 사항을 제한합니다.
그리고 그에 맞게 프로그램을 개발합니다. 

이때 이 분들이 작성한 프로그램을 보면 ( 무정전 제품에 
들어가는 프로그램일수록 ) 전역변수와 배열을 많이 사용하게
됩니다. 

이 전역변수와 배열을 사용하는 것은 
프로그램을 처음 배울때 회피하라고 들었던 것인데 
의외로 고수일수록 많이 사용합니다.
(심지어 goto 문을 남발하시는 고수도 많습니다. )

배열을 사용한다는 것은 일정한 크기를 갖기 때문에 
확장성에 용이하지 않을 것 같은데 
환경 파일로 모든 확장성을 고려하는 것은 임베디드 
제품에 크게 의미가 없읍니다. 

이미 한정된 크기의 메모리를 가지고 있는 시스템에 
확장할수 있는 크기를 가지도록 프로그램을 작성한다는 것은 
의미가 없읍니다. 


배열을 사용하게 되면 다음과 같은 장점이 있읍니다 

1) 메모리 할당과 해제와 관련된 버그가 없다. 
2) 메모리 할당과 해제에 소모되는 시간 소모가 없다. 
3) 인덱스 방식의 참조가 가능하므로 잘못된 포인터 
참조에 의한 버그 가능성이 작다. 
4) 시스템의 메모리를 효율적으로 사용할수 있다. 
5) 참조 속도가 매우 빠르다.
6) 프로그램 소스 코드가 직관적이다. 
( 포인터 참조 연산자가 얼마나 어려운 코드 형식을 
작는지 다들 아시죠? )

등등의 장점이외에 더 있지만 생각이 안 나는 군요...

어쩄든 임베디드 장비에 사용되는 프로그램은 가급적 배열을 
사용하시는 것이 좋습니다. 

3. 가급적 상수를 매크로로 정의해서 사용하라

메모리 이야기에 왠 매크로 상수?

뭐 이렇게 궁금하게 생각하시는 분들이 있을 것 같은데...
이래야 고수 소리를 듣습니다. 소스에 숫자가 적게 보일수록 고수 입니다 


예를 들어 보죠...

어떤 분은 프로그램을 이렇게 작성합니다. 

char check_ids[300];

고수는 이렇게 작성합니다. 

#define MAX_CHECK_IDS 300
char check_ids[MAX_CHECK_IDS];


이것은 나중에 확장성을 가지는 효과가 있고 
접근하는 인덱스의 검사를 할 경우에 유용합니다. 


또한 인데스 검사를 하는 경우에 유용합니다.
보통 프로그램을 작성할때 인덱스 접근에 대하여
다음과 같이 처리하면 좋습니다. 


char get_date( int index )
{
#ifndef NO_CHECK_INDEX_FLAG
if( (index < 0) || (index >= MAX_CHECK_IDS ) )
{
dlp( "index over\n" );
exit(0); 
}
#endif
return check_ids[index];
}

또는 아예 인덱스 검사를 하는 함수를 매크로로 만들어서 사용하는 경우도 있읍니다. 

선언예)

#ifndef NO_CHECK_INDEX_FLAG
#define check_index(idx,max) {\
if( (index < 0) || (index >= MAX_CHECK_IDS ) ) \
{ \
dlp( "index over\n" ); \
exit(0); \
} \

#else 
#define check_index(idx,max) {}
#endif 


사용예)

char get_date( int index )
{
check_index(index,MAX_CHECK_IDS);
return check_ids[index];
}

3. 초기화를 꼭 하라

변수를 사용할때 특히 전역 변수를 사용할때 
초기화를 하는 습관은 버그를 예방하는 효과가 있읍니다. 
특히 포인터 형식의 필드변수를 포함하는 구조체가 있을 경우에는 특히나 그렇습니다.

초기화 값은 0으로 사용하는 것이 좋습니다. 
포인터의 

4. sizeof 함수를 즐겨 사용하라 

메모리 복사나 초기화를 사용할 경우와 같이 배열이나 구조체의 크기를 구할 필요가 
있을때 sizeof 를 자주 사용합니다.

귀찮아서 그냥 숫자를 주는 습관을 가진 분들이 있는데 
이런 분들에게 sizeof 함수의 사용을 강력하게 권장합니다. 

앞의 배열에서 초기화를 처리할때 다음과 같은 형식으로 처리하는 것이 좋죠...

memset( check_ids, 0, sizoef( check_ids ) );

복사할 경우에 역시 이런 식으로 사용하는 것이 좋습니다. 
하지만 복사할 경우에 크기는 어느 것을 사용하는 것이 좋을까요?
권장하는 것은 앞에것을 사용 하는 것입니다 

void copy_item( struct a *bdata )
{
struct a adata;

// 권장하는 예 
memcpy( &adata, bdata, sizeof( adata ) ); 

// 별로 권장하지 않지만 좋은 예 
memcpy( &adata, bdata, sizeof( struct a ) ); 


}


5. 포인터의 간접 인덱스를 사용할 때는 주의하라...

포인터 변수를 사용할때 포인터의 초보자들이 실수하는 큰 것 
중에 하나는 다음입니다. 
특히 하드웨어를 다룰때 많이들 실수 합니다. 

char *app;
int *bpp;

app++;
bpp++:

이것은 1씩 증가 시키는 겁니다. 
그런데 app 나 bpp 에 0x300000 이라는 주소값이 있다면
app는 0x30000 이 되지만 bpp 는 0x300004 가 된다는 것을 
까먹습니다. 

이것이 나중에 속썩일 경우가 많다는 점을 기억하십시오

(app+ 1) 과 (bpp+ 1) 도 마찬가지 입니다. 
이런것은 매크로를 사용해서 선언할 경우 많이들 실수하는 겁니다. 

예를 들어 하드웨어 레지스터를 접근하는 경우에 

#define REG_A(x) (x + 1)
#define REG_B(x) (x + 2)

이런식으로 처리할때 매크로는 단순히 문자열 치환이기 때문에 
위와 같은 문제가 발생할수 있다는 것입니다.


6. 스택변수 즉 로컬 변수를 조심하자 

함수안에 선언하는 로컬 변수는 두가지 장점이 있읍니다. 

선언이 간단하고 할당에 걸리는 시간이 없다는 것입니다. 
그러나 이 로컬 변수는 버그의 온상이 되므로 주의할 필요가 있습니다. 

예를 들어 다음과 같은 경우를 생각해 봅시다. 

int test_func( char *tmpstr )
{
char buff[32];
int p;

p = strlen( tmpstr) ;

sprintf( buff, "ID:%s", tmpstr );
write_func( buff );

return p;
}

이 함수를 소스상에서 본다면 아무런 문제가 발생하지 않는 함수입니다.
그런데 이 함수는 두가지 문제점을 가지고 있읍니다. 

만약 tmpstr 이 NUL 코드를 포함하지 않는다면?
또는 tmpstr 이 28 자 이상이 된다면 ?

아...

프로그램은 어떻게 동작할지 아무도 장담할 수 없읍니다. 

다행히 세그먼트 폴트라도 발생해서 미리 알수있다면 좋지만
스택을 접근 할 경우에는 세그먼트 폴트가 잘 발생하지 않습니다. 

경우에 따라서는 스택이 깨지기 때문에 엄한 곳으로 프로그램이 점프할수도 있고 
다른 변수들이 수정될수도 있읍니다.

더구나 특별한 경우에는 두번 호출되어 도착한 함수가 꺼꾸로 리턴될때 
중간 함수를 거치지 않고 리턴되거나 진행 루틴이 실행되지 않을 경우도 있읍니다. 

또는 뒤에 선언된 변수들 값이 수정될수도 있읍니다. 

이런 경우에는 스택 변수의 크기를 아끼지 않는 것이 가장 최선의 예방책입니다. 
(물론 주의해서 작성하는 것이 더 큰 최선의 에방책이죠.. )

예를 들어 넘어온 크기보다 2 배나 3 배정도의 크기를 잡는 겁니다. 

위의 경우에는 char buff[128] 정도로 선언하는 것이 안전합니다. 

또는 버퍼의 뒷쪽에 임의 변수를 하나 두는 것도 요령인데 
별로 추천은 하고 싶지 않군요


7. 자료구조를 사용한다면 검증된 라이브러리를 사용하라..

프로그램을 작성하다보면 배열보다 리스트와 같은 자료구조를 
이용하는 것이 효율적일때가 있읍니다. 

대표적인 것들이 

스택이나 , 큐, 더블 링크드 리스트 , 리스트, 이진 트리 리스트
등등이 있읍니다. 

이때 많은 분들은 직접 만들어 사용합니다. 

그런데 이런 처리는 포인터를 사용해야 하고 저같이 논리에 약한
사람들이 만들면 버그가 살기에 좋은 환경을 제공합니다. 

그래서 저는 인터넷에 관련 자료 구조용 공개된 소스를 이용하기를 
권장합니다. 

특히 소스포지에 가면 이런 자료 구조체 라이브러리들이 많이 있읍니다.
가급적 이렇게 공개되고 여러사람이 사용하고 있는 것을 이용하기를 
바랍니다.

직접 만들면 피 봅니다... ㅜㅜ

8. 메모리 할당 함수들 

C 에서 메모리를 할당하기 위해서 사용하는 함수들은 다음과 같습니다. 

void *calloc(size_t nmemb, size_t size); // 할당 + 메모리 클리어 
void *malloc(size_t size); // 할당
void free(void *ptr); // 해제 
void *realloc(void *ptr, size_t size); // 재 할당 + 메모리 복사 

이 중에서 가장 많이 사용하는 함수는 

malloc 함수와 free죠...

하지만 malloc 함수보다는 calloc 함수를 사용하기를 권장합니다.
(저역시 malloc 함수를 자주 사용합니다만 ㅜㅜ )
그래도 malloc 함수를 자주 사용하게 되면 다음과 같은 처리를 꼭 해주시기를 바랍니다. 

char *buff = NULL;

buff = malloc( 1000 );
if( buff != NULL )
{
memset( buff, 0, 1000 );
}
else
{
// 에러 처리 ( 보통은 프로그램을 죽인다. )
}

if( buff != NULL ) free( buff );


9. assert 함수


앞에서 malloc 함수를 처리할때 에러가 난 경우에 대한 처리가 귀찮죠?
이런 경우 사용하거나 기타 등등에 사용하면 좋은 함수가 assert 함수입니다.


이 함수는 #include <assert.h> 를 포함하고 사용하면 되는데 
사용 문법은 간단합니다. 

assert( 논리식 );

이 함수는 논리식이 참이면 특별한 것을 하지 않습니다. 
그러나 거짓이면 에러를 표현 합니다. 
파일명과 함수명 그리고 라인번호와 함께 문제가 된 값을 표현합니다. 
그리고 프로그램을 죽입니다.( 으으 살벌.. )

보통은 포인터 변수의 값이 0이 되는 것을 방지하기 위해서 사용합니다. 

assert 함수는 NDEBUG 가 정의 되어 있으면 아무런 것도 하지 않는 
함수이므로 소스를 수정하지 않고서도 함수의 에러 처리를 무효화 
할 수 있는 무척 좋은 함수 입니다.



modaless의 경우 대화상자가 떠있는 상태에서 얼마든지 다른 작업을 할 수 있다.

modal의 경우 대화상자가 닫히기 전까지 다른 작업을 할 수 없다.


modal 형태로 창을 띄우는 것은 


CShapeDlg dlg;

dlg.DoModal(); // 이런 형태로 창을 띄우는 것이다.


modal로 창을 띄우는 경우, 이 창을 먼저 해결해야 부모 창으로 돌아갈 수 있다.




그리고 modaless 형태로 창을 띄우는 것은


CShapeDlg *dlg;


dlg = new CShapeDlg(); //혹은 CShapeDlg(this); 등으로 초기화 한 후

dlg->Create(IDD_SHAPE, NULL) //혹은 Create(IDD_SHAPE, DesktopWindow()); 등을 써서 만들어주고,

dlg->ShowWindow(SW_SHOW) //혹은 dlg->ShowWindow(SW_SHOWNA); 등등 으로 창을 띄워주면 된다.


//initDialog등을 처리해주고싶다면 

dlg->PostMessage(WM_INITDIALOG)

dlg->SendMessage(WM_CLOSE) //등을 넣어서 창을 닫아 줄 수 있다.




CDialog에 있는 OnTimer


OnTimer라는 메세지 핸들러는 SetTimer(타이머ID, 발생간격, 실행하려는 함수명)​과 함께 사용한다

// ​여기서 함수명에 NULL을 넣어주면 OnTimer를 사용


일정 시간 뒤에 원하는 업무를 처리하기 사용한다.

 

비슷한 기능으로 Sleep( millisecond ) 를 입력하는데

Sleep을 이용할 경우 해당 쓰레드 전체가 멈추어 버리고 그 멈춤에 따라 외부 인터럽트입력(키보드, 마우스, 등등)이

주어지게 되면 버퍼에 쌓였다가 한번에 처리되는 일이 발생하게 된다.

 

그래서 그걸 방지하기 위해 Timer를 사용하는데 사용방법은 다음과 같다.

 

 

 

등록

 BEGIN_MESSAGE_MAP(CGroupChatWindow, CDialog)

...

ON_WM_TIMER()

...

 END_MESSAGE_MAP()

메세지 맵에 'ON_WM_TIMER()'를 등록

 

 

타이머 시작

 SetTimer(1394,1000,NULL);

  파라매터

1) Timer의 ID값

2) SetTimer후 몇 millisecond후 마다 실행 (반복실행)

3) 함수명, NULL 사용시 오버라이드 함수 'OnTimer()'로 작동된다.

  반환값 : 핸들러

 

 

 

선언

 afx_msg void OnTimer(UINT nIDEvent);

헤더파일에 선언

 

 

 

오버라이드 함수 내부

 void CGroupChatWindow::OnTimer(UINT nIDEvent)
 {
    switch(nIDEvent)
    {
        case 1394:

             limitLatencyClickAble = TRUE;   
             mCheckSendVoice.EnableWindow(TRUE);

             break;
    }

    KillTimer(1394);
}

switch문을 사용하여 Timer의 ID를 구분하여 처리

SetTimer에 첫 파라매터에 1394를 적었기에 OnTimer( )에서는 switch문에 case로 1394

 

 

 

타이머 중지

 KillTimer(1394);

타이머 아이디를 입력하면 끝


virtual BOOL CWnd::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult );


리턴

이 메시지를 처리한다면 어플리케이션은 0이 아닌 값을 리턴하며, 그 외는 0을 리턴한다.


인수

wParam : 메시지가 컨트롤로부터 왔다면 그 메시지를 보내는 컨트롤을 식별한다. 그 외는 0값을 가진다.

lParam : 신호 코드와 부가적인 정보를 가진 기 메시지 (NMHDR) 구조체의 포인터. 어떤 기호 메시지들에서, 이 인수는 그것의 첫째 멤버처럼 NMHDR 구조체를 가지는 더 큰 구조체를 가르킨다.

pResult : 메시지가 핸들되었다면 결과 코트를 저장할 LRESULT 변수의 포인터


설명

프레임워크는 컨트롤 이벤트가 일어나거나 그 컨트롤이 어떤 종류의 정보를 요구하는 컨트롤의 부모 윈도우에게 알리기 위해 이 멤버 함수를 호출한다.


OnNotify는 컨트롤 신호에 대한 메시지 맵을 처리한다.

 

 

Example

 

- header file 부문

// ClassWizard generated virtual function overrides

virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);

 

- implementation file 부문

BOOL CIconExDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{
     // TODO: Add your specialized code here and/or call the base class

     NMHDR* pNMHDR = (NMHDR*)lParam;

     switch (wParam)
     {
     case IDC_R:
          if(pNMHDR->code == TCN_SELCHANGE)
          {
               // IDC_R을 눌렀을 경우 행해지는 소스 입력
          }
          else
          {

               // IDC_R을 땟을 경우 행해지는 소스 입력
          }
          break;

     case IDC_RIGHT:
          // IDC_RIGHT을 눌렀을 경우 행해지는 소스 입력
          break;
     }


     return CDialog::OnNotify(wParam, lParam, pResult);
}

+ Recent posts