#pragma는 단순히 define나 include와 같이 #으로 시작되는 전처리문의 하나입니다.

대단한 용법은 아닙니다.

다만 편의성과 기능성을 제공해 주죠.

현재 자신이 사용하고 있는 컴파일러가 이녀석을 지원해 준다면

이전글에서 헤더파일 중복문제 해결을 위한 방법보다 좋은 성과를 보여줄 겁니다.

이전글의 내용이 생각나지 않는 분을 위해 이곳에 이전글의 핵심 내용을 간단히 보여 드리죠.

 

// 헤더 파일의 제일 첫 부분
01: #ifndef HDR_H     // 헤더 파일명을 대문자한 매크로가 정의되어 있지 않으면
02: #define HDR_H    
// 헤더 파일명 매크로를 정의한다

......                // 헤더 파일 본 내용이 여기 들어갑니다

03: #endif            // ifndef HDR_H 에 매치됩니다

 

위와 같이 헤더 파일을 작성하게 되면 다음과 같은 과정이 일어나게 됩니다.

컴파일러와 역지사지해서 생각해 보겠습니다.

1. 처음으로 헤더 파일이 포함될 때, 컴파일러(좀 더 정확히 말하면 프리프로세서)가

01 라인을 만나게 되면 HDR_H 매크로가 정의되어 있지 않으므로 02 라인을 해석하게 됩니다.
2. 02 라인을 만나면 이제 HDR_H 매크로를 정의하게 됩니다.
3. 다음에 다시 같은 헤더 파일이 포함될 때는 HDR_H이 정의되어 있기 때문에

모든 헤더 파일의 내용을 스킵하게 됩니다. 즉, 포함되지 않는 효과가 생기게 됩니다.

 

이러한 방법을 include guard (포함 보호)라고 합니다.

이 방법도 무척 훌륭한 방법입니다.

다만 사용자 입장에서 실수할 여지가 많다는 겁니다.

매크로 이름의 충돌가능성등 말이죠.

물론 어지간한 프로젝트에서는 이런 일은 발생하기 어려울 겁니다 ^^a...

그리고 include guard는 한번 읽은 헤더파일도 일단 헤더파일의 내용을 다 읽어야 합니다.

시간낭비고 컴파일러 컴력 낭비(ㅡㅡ;) 이고 효율낭비이죠.

 

pragma는 이러한 면에서 확실히 뛰어납니다.

이녀석의 경우는 각 파일별로 프리프로세서가 include한 상태를 기억하고 있어서

한번만 include한다면 이후로 다시 읽어야하는 지루한 일은 안한다는 겁니다.

 

오~ pragma녀석... 무척좋군~

하시는 분도 있을겁니다.

하지만 안타깝게도 이녀석은 표준이 아닙니다.

즉, 이녀석을 사용하여 프로그램을 짠다면 다른 어떠한 환경에서는

이녀석을 지원해주지않는일을 보게 될 겁니다.

그 외에도 문제가 있지만 가장 큰 문제는 표준이 아니라는 점이죠.

 

그럼 이제 슬슬 고민이 되겠죠?

도대체 어떤놈을 써란말이야~~!!

결론은 이겁니다. 내부 포함보호와 외부 포함보호를 적절히 활용하라.

이전에 헤더파일 중복 문제해결방법은 내부 포함보호방법이었죠.

 

#ifndef HDR_H
#include "hdr1.h"
#endif

 

요런방법이 외부 포함 보호방법입니다.

이 방법을 사용하면 include guard의 문제점인 컴파일 속도측면에서의

비효율성 문제를 극복할 수 있습니다.

 

기억하세요.

손쉽고 편한 pragma 를 사용하여 이식성을 한껏 낮추는 것 보다는

내부 - 외부 포함 보호 방법을 적절히 활용하여 헤더파일 중복을 막는것이

더 올바른 자세란 것을요.


출처 - http://blog.naver.com/khercules

'프로그래밍 기초 > C' 카테고리의 다른 글

extern  (0) 2010.02.21
Posted by 아몰라
2010. 2. 21. 02:32
 

프로그램이 만들어지는 과정에는

전처리기 - 컴파일 - 링킹 - 실행파일생성 이런 단계로 이루어져있다.


전처리기
는 앞에 #이 붙은 것들을 처리하는데

특정 함수나 변수가 있는 라이브러리들을 끌어올때 사용한다.


컴파일
은 라이브러리를 참고해서 각각 특정언어로 작성된 코드들을

기계어코드인 오브젝트파일로 바꾸어준다.

extern 키워드는 선언한 변수나 함수가 현재 파일에는 없고 다른곳에 정의된

것이라는 것을 컴파일러에 알려주는 목적으로 사용된다.


마지막으로 링킹과정은 생성된 오브젝트들을 연결을 시켜서 하나의

실행파일로 만드는 과정이다.


컴파일 과정에서 에러가 나지 않았지만 링킹과정에서 에러가 발생하는 경우가 많이 있는데

그것을 컴파일때에 함수 정의나 변수가 없더라도 다른곳에서 선언되었다고 컴파일러가 묵시적으로 이해를 하는데,

링킹과정에서 그 함수, 변수를 못찾아서 에러가 발생하는 경우이다.
(extern으로 .h파일에 변수를 명시적 선언했지만 c파일에서 실질적으로 선언하지 않은경우)

 

extern 으로 선언된 변수는 컴파일러에게 요 변수가 다른곳에서 정의되어 있다는 것을 알려준다.

컴파일 타이밍에 메모리에 잡히지 않고  단지 컴파일러에게 이러한 변수가 있으니 현재 파일을 컴파일 할때 에러를 보내지 말라고 알려주는역할을 한다.

'프로그래밍 기초 > C' 카테고리의 다른 글

헤더파일중복문제  (0) 2010.02.21
Posted by 아몰라

 

RESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);


첫번째 인수(HWND hWnd) : 메시지를 받을 윈도우 핸들. 클래스로부터 여러 개의 윈도우가 만들어

졌을 때 어떤 윈도우로 전달된 메시지 인지를 구분해야 하므로 이 인수가 필요함.

두번째 인수(UINT iMessage) : Message ID이며 0x00 ~ 0x3FF 사이의 값이다. “WM_”으로 시작하는 상수로 정의 되어 있다.(전달된 메시지의 값)

WPARAM wParam, LPARAM lParam : 32비트 정수값이며 메시지의 추가 정보를 가진다.


메시지 큐


 

 

메시지는 시스템이나 사용자에 의해 발생한다.

키보드나 마우스 등의 사용자 입력 시 시스템은 이 입력에 대해 메시지를 발생시키며 또한

시스템 상황 변화를 통지하기 위해서도 메시지를 발생시킨다. 응용 프로그램도 윈도우간의

통신을 위해 메시지를 발생하며 특정 함수 호출에 의해 간접적으로 메시지가 발생하기도 한다.

윈도우즈라는 운영체제는 끊임없는 메시지의 생성과 처리를 무수히 반복하면서 실행되는

것 이므로 메시지는 윈도우즈 운영체제에서 중요하다고 할 수 있다.

메시지는 크게 메시지큐로 들어가는 (Queued)메시지와 큐에 들어가지 않고 곧바로

윈도우 프로시저로 보내지는 비큐(Non Queued)메시지로 구분된다.



 

윈도우 프로시져(Window Procedure) : 메시지를 처리하는 함수

 

- 윈도우 클래스당 하나씩 배정되며 메시지에 대응하는 방식을 정의하여 윈도우의 행동 양식을

   결정한다.

- 윈도우 클래스로부터 생성된 모든 윈도우의 메시지는 이 함수가 처리한다.

- 이름은 사용자가 마음대로 바꿀 수 있으나 일반적으로 WndProc이라는 이름을 사용한다.

- 4개의 인수를 가지며 정수값 하나를 리턴한다. 대부분 잘 처리했으면 0을 리턴하지만 어떤

   메시지는 처리 결과를 운영체제로 리턴하여 보고하는 경우도 있다.

Ex) WM_CREATE 는 초기화 과정에서 에러가 없으면 0을 리턴 에러가 발생했으면 -1을 리턴한다.

      WM_NCHITTEST  는 마우스가 윈도우의 어떤 부분에 있는지를 리턴한다.

  *WM_NCHITTEST : 윈도우에게 커서가 움직이거나 마우스버튼이 눌리거나 띄어졌을 때 메시지를 보낸다.



 




v  Window Procedure

모든 윈도우는 메시지를 처리하기 위해 메시지 처리 함수가 있어야 한다. 메시지 처리 함수의 모양은 아래 같다.

LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

윈도우 클래스를 만들때 메시지 처리함수의 주소를 등록한다.

v   Non-Queued Message

사용자가 윈도우를 만들기 위해 CreateWindowEx()함수를 호출하면 윈도우가 만들어 지고 윈도우가 만들어 졌다는 사실을 사용자에게 알리기 위해 WM_CREATE라는 메시지가 메시지 처리함수에 전달된다.(메시지 처리 함수가 호출된다.)

이때 WM_CREATE 메시지는 Message Queue 놓이지 않고 직접 Window Procedure 전달 되는 이를 non-Queued Message라고 한다.

입력 메시지(마우스 메세지, 키보드 메시지) 제외한 대부분의 메시지가 non-Queued Message 이다.

 

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {

switch( msg )     {

case WM_CREATE:

                           MessageBox( 0, "WM_CREATE도착", "", MB_OK);

                           return 0;

  

}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE , LPSTR lpCmdLine, int nShowCmd)

{

HWND hwnd = CreateWindowEx(…);

ShowWindow(hwnd, nShowCmd);






v  Queue Message

마우스나 키보드 메세지들은 직접 Window Procedure 전달되지 않고 메시지 Queue 놓이게 되는데 이를 Queue Message라고 한다. Queue 놓인 메시지를 처리하려면 반드시 사용자가 Queue 놓여 있는 메시지를 가져오는 메시지 루프가 필요하다.

MSG msg;

while ( GetMessage( &msg, 0, 0, 0 ) )  {

       TranslateMessage(&msg);

       DispatchMessage(&msg);

}

GetMessage() 메시지 Q WM_QUIT 메시지가 있을 경우에만 FALSE 리턴한다. 그래서 코드는 WM_QUIT메세지가 Q 들어 올때 까지는 무한 루프가 된다.

v   프로그램의 종료

사용자가 만든 윈도우가 파괴될 나오는 메시지는 WM_DESTROY 이다. 그러므로 사용자가 윈도우를 파괴 해도 프로그램은 계속 메시지 루프를 돌게 된다.( 하지만 윈도우는 파괴 되었다.- 모니터 화면에는 이상 아무 것도 없다.)

윈도우를 1 만든 경우 프로그램의 main 윈도우가 파괴 프로그램을 같이 종료 되게 하려면 WM_DESTROY 메시지에서 WM_QUIT메세지를 메시지 Q 넣는 작업을 해야 한다.

case WM_DESTROY:

       PostQuitMessage( 0 );             return 0;

v   처리하지 않은 메시지

메시지 처리 함수에서 발생된 메시지를 처리하지 않은 경우 반드시 아래 함수로 보내서 default 처리가 되게 해야 한다.

LRESULT CALLBACK DefWindowProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);









메시지 루프

 

- 사용자에 의해 입력된 메시지는 시스템 메시지 큐에 일단 저장되고 스레드 메시지 큐로 이동했다가 메시지 루프에 의해 해당 윈도우의 윈도우 프로시저로 보내져 처리된다.

 - 메시지는 최종 처리되기 직전까지 계속 큐에 유지되는데 이때 메시지는 다음과 같이 정의된 구조체의 형태로 존재한다.


Typedef struct tagMSG{HWND hwnd; UINT message; PARAM wParam; LPARAM lParam; WORD time; POINT pt;}MSG;


HWND
hWnd : 메시지를 받을 윈도우 핸들.

UINT iMessage : 전달된 메시지의 값

WPARAM wParam, LPARAM lParam : 메시지의 추가 정보를 가진다.

 

DWORD time : 메시지가 발생한 시간(time)

POINT pt : 발생시의 마우스 좌표(pt)

시간과 마우스 좌표는 모든 메시지들이 필요로 하는 정보가 아니므로 WndProc까지 전달되지 않는다.
필요할 경우 다음 두 함수를 사용하여 직접 조사해야 한다.

      ※ DWORD GetMessagePos(VOID) : 하위워드(LOWORD)x좌표, 상위워드(HIWORD)y좌표를 리턴한다.

      ※ LONG GetMessageTime(VOID) : 메시지 발생 시간을 부팅된 후 경과된 1/1000 단위로 리턴한다.


 

 - 메시지 루프는 메시지 큐에서 메시지를 꺼내 메시지 처리 함수로 보내는 일을 한다.

 - 보통 WinMain의 제일 끝부분에 위치하며 다음과 같이 그 형태가 정형화 되어 있다.


while(GetMessage(&Message,NULL,0,0)

{

     TranslateMessage(&Message);

     DispatchMessage(&Message);

}


- while문에 싸여져 있는데 이 루프는 프로그램이 끝날 때까지 계속반복된다.

    (메시지큐에 WM_QUIT[kwɪt]이라는 윈도우 메시지가 도착해 있으면 위의 반복문 조건속에 있는

     GetMessage함수는 FALSE값을 리턴하고 종료한다.)

      * WM_QUIT : PostQuitMessage 함수가 실행되면 발생하는 메시지

 

BOOL GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);

 

 - 스레드 메시지 큐에 대기중인 메시지를 꺼내 첫 번째 인수로 전달된 MSG 구조체에 복사한다.

 - 복사한 메시지를 큐에서 제거하고 TRUE리턴하며, 만약 큐에서 가져온 메시지가 WM_QUIT이면

    FALSE 리턴하여 메시지 루프를 탈출할 수 있다.

 

LPMSG lpMsg : MSG 구조체의 번지를 지정한다.

HWND hWnd : 현재 메시지를 큐에 올린 윈도우의 핸들값. 메시지를 처리해서 되돌려 줄때 필요하다.

UINT wMsgFilterMin : 회수된 메시지의 범위 중 최소값을 정수형태로 지정

UINT wMsgFilterMax : 회수된 메시지의 범위 중 최대값을 정수형태로 지정

 

*wMsgFilterMin : 첫번째 키보드 메시지인 WM_KEYFIRST 메시지 혹은 첫번째 마우스 메시지를 저장하는 WM_MOUSEFIRST 메시지 정수값을 저장한다.

*wMsgFilterMax : 마지막 키보드 메시지인 WM_KEYLAST 메시지 혹은 마지막 마우스 메시지를 저장하는 WM_MOUSELAST 메시지 정수값을 저장한다.

*wMsgFilterMin, wMsgFilterMax에 메시지의 범위를 지정하면 이 범위 내의 메시지만 가져온다.

*wMsgFilterMinwMsgFilterMax 인자의 값이 둘 다 0이면  GetMessage함수는 메시지 사용범위의  지정없이  모든 메시지를 돌려준다.

 

TranslateMessage


 
GetMessage 함수에 의해 큐로부터 가져온 메시지는 WM_QUIT가 아닌 한은 TranslateMessage 함수로 전달된다. 이 함수는 가상키 입력을 문자 입력(WM_CHAR)으로 바꾸는 역할을 하며 가상키 입력이 아닌 경우는 아무 처리도 하지 않는다.

* 컴퓨터의 가장 기본적인 입출력 장치는 아직까지는 키보드이다. 입력이 발생했을 경우 윈도우즈는 포커스를 가진 프로그램에게 키보드 메시지(WM_CHAR)를 보내주며 프로그램은 이 메시지를 받아 키보드 입력을 처리한다.(포커스(FOCUS)를 가진 프로그램이란 활성화되어 있는 윈도우를 말하며 한번에 오직 하나의 프로그램만 활성화 된다.멀티 태스킹 환경이라도 활성화될 수 있는 프로그램은 오직 하나밖에 없으며 활성화된 프로그램만 포커스를 가지고 키보드 입력을 받아들일 수 있다.


 

 DispatchMessage


메시지를
윈도우 프로시저로 보내 처리하도록 하는데 MSG 구조체의 hwnd 멤버를 보고 정확하게 목적 윈도우의 메시지 처리 함수로 배달한다. 윈도우 핸들로 부터 어떤 윈도우 프로시저에게 메시지를 전달할 것인가를 결정하는 중요한 일을 이 함수가 담당한다.




출처 - 선문비트 최강사님 도큐먼트

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

프로세스  (0) 2010.02.10
ATOM  (0) 2010.02.09
간단한 DLL 예제  (1) 2010.02.03
리스트뷰  (0) 2010.02.03
WM_USER And WM_APP  (0) 2010.02.02
Posted by 아몰라