728x90
반응형
[ C 언어 ]
main 함수 위에 정의하는것은 무엇이 있을까?
구조체 정의
함수 원형 정의
#define
#include
enum 정의
...
함수 원형 정의
#define
#include
enum 정의
...
그렇다면 어떤 것을 먼저 정의를 해야 할것인지에 대한 의문이 생긴다. 이 문제를 해결하기에 앞서 왜 main 함수 위에 정의를 해야하는지 부터 생각해봐야한다. C 언어는 절차지향언어이다. 이 말은 컴파일러가 컴파일을 할 때 한 라인씩 절차적으로 진행을 한다는 말이다. 즉 어떠한 라인에서 컴파일을 진행하는 것은 이전의 컴파일은 완벽하게 되었음을 의미한다. 그러므로 main 함수에서 사용하기 위한 각종 정의에 대해서는 미리 컴파일이 되어 있어야한다. 미리 컴파일이 되어 있다는 것은 이전에 컴파일 되었던 것이 필요하다는 의미이다. 즉 이전에 컴파일 되었던것에 의존이 필요하다는 의미다. 이러한 의미로 부터 알 수 있다. 어떤 것을 먼저 정의를 해야 하는 것인가에 대한 해답은 의존성이 낮은 것을 최상위에 정의를 하는 것이다. 그럼 의존성이 낮은 것을 찾아보자. 다음 예를 살펴보자.
struct A { FILE *fp; };
고수준의 파일 입출력 구조체 포인터를 구조체 A 에서 멤버변수로 사용해보자. 그럼 이 구조체를 사용하기 위해서는 무엇이 필요 하겠는가?? stdio.h 헤더파일이 필요할 것이다. FILE 구조체는 stdio.h 헤더파일에 정의되어 있기 때문이다. 결국 이 구조체 A 는 stdio.h 헤더파일을 의존해야한다. 그러므로 #include <stdio.h> 가 먼저 정의되어야한다.
함수의 경우에는 함수의 인자로 구조체 포인터를 사용한적이 있지 않은가?? 따라서 함수의 경우는 구조체보다 의존성이 더 크게 되므로 구조체보다 밑에서 정의된다. 물론 예외는 있다. 구조체 멤버변수에 함수포인터 변수가 사용된다면?? 이야기는 달라진다.
결국 정리를 해보면 일반적으로는 다음과 같이 정의를 하면 될 것이다.
#include
#define
enum 정의
구조체 정의
함수 원형 정의
#define
enum 정의
구조체 정의
함수 원형 정의
여기서 주의할 것은 무조건적으로 이 순서가 맞다고 할 수 없다. 상황에 따라 의존성이 달라질 수 있음을 항상 생각하고 있어야 한다.
다음 예제를 살펴보자.
#include <stdio.h> #include <string.h> void monday(); void tuesday(); void wednesday(); void thursday(); void friday(); void saturday(); void sunday(); struct MessageMap { const char *name; void (*fp)(); }; struct MessageMap map[] = { {"Monday", monday}, {"Tuesday", tuesday}, {"Wednesday", wednesday}, {"Tursday", thursday}, {"Friday", friday}, {"Saturday", saturday}, {"Sunday", sunday}, {0, 0} }; enum day_num { MON, TUE, WED, THU, FRI, SAT, SUN, END };
main 함수의 위에 정의되어 있는 부분을 살펴보자. 여기에서는 무엇을 먼저 정의를 해야 할까? 우선 #include 는 앞서 알아봤듯이 의존성이 낮기 때문에 먼저 정의를 해둔다. 그 다음으로는 enum 이 될것이다. 아무런 의존을 하지 않는다. 하지만 구조체를 잘 살펴보자. 구조체의 멤버 변수에는 함수 포인터 변수를 가진다. 따라서 함수의 정의가 없다면 구조체는 함수의 대해 알지 못할 것이다. 따라서 함수의 원형의 정의에 대한부분에 의존성을 가지는 셈이다. 따라서 함수의 정의가 먼저 나와야 할 것이고 그 후에 구조체가 나와야 할 것이다.
main 함수의 구현 부분이다.
위의 소스 코드는 Message Map 기법을 사용하였다. main 함수를 변경할 필요가 없이 메시지 맵을 수정하고 수정된 기능에만 집중하면 된다. 이로인해 빠르고 안정적이며 수정이 용이해진다. 메세지 기반을 사용하는 Windows 프로그래밍에서는 Message Map 기법을 사용한다.
union 에 대해서 알아보자. 구조체와 유사하게 생겼지만 멤버들이 메모리를 공유한다는 점에서 다르다. 멤버들 중 가장 큰 공간을 가지는 자료형을 사용하여 공유한다. 무슨 소리인가 하면 다음 소스를 살펴보자.
#include <stdio.h> //typedef struct emb typedef union emb { unsigned int A; unsigned short B; unsigned char C; }EMB; int main() { EMB test; test.A = 0x12345678; test.B = 0xAAAA; test.C = 0xBB; printf("test.A : %08x\n", test.A); printf("test.B : %08x\n", test.B); printf("test.C : %08x\n", test.C); printf("\n"); test.A = 0x11223344; printf("test.A : %08x\n", test.A); printf("test.B : %08x\n", test.B); printf("test.C : %08x\n", test.C); printf("\n"); printf("&test.A : %08x\n", &test.A); printf("&test.B : %08x\n", &test.B); printf("&test.C : %08x\n", &test.C); printf("\n"); printf("test size : %d\n", sizeof(test)); return 0; }
위의 소스에서 union 의 선언은 다음과 같다.
typedef union emb
{
unsigned int A;
unsigned short B;
unsigned char C;
}EMB;
unsigned int 형이 가장 큰 자료형이므로 4 byte 의 공간을 서로 공유한다. 또한 공간을 공유하므로 공용체 변수 test 의 크기는 4 byte 의 크기를 가지게 된다. 또한 멤버들이 사용하는 공간이 같으므로 주소 역시 같다. 다음 결과를 살펴보면 알 수 있다.
같은 공간에 4 byte 공간에 Little Endian 으로 저장되므로 다음과 같이 저장된다.
결국 위의 그림의 3 번째와 같이 저장되며 각 멤버의 타입의 크기에 따라 출력을 하게된다.
위와 똑같이 구조체를 사용하여 출력하면 다음과 같다. 서로 공간을 공유하지 않기 때문에 각각의 멤버는 각자의 타입에 맞는 공간을 가지며 구조체의 크기 역시 커진다. 결과는 다음과 같다.
<const>
선언과 동시에 초기화를 할 수 있지만 초기화를 한 순간 부터는 수정할 수 없다.
포인터 변수의 경우를 살펴보자.
const int *ip
항상 정수형 상수를 가리켜야 한다.
int *const ip;
항상 같은 주소를 가리켜야한다.
const int * const ip;
항상 같은 주소를 가리키면서 항상 정수형 상수를 가리켜야 한다.
함수의 인자에 사용되는 예로써 문자열 함수 strlen() 의 원형을 살펴보자
int strlen(const char *string);
가리키는 대상은 반드시 문자열이여야 한다. 가리키는 대상이 char 형이기 때문이다. 하지만 string 이 가리키는 문자열 자체는 변경되어도 문제가 없다.
<volatile>
컴파일러에게 volatile 로 선언된 변수는 최적화를 하지 않도록 하는 예약어이다.
<조건연산자>
3항 연산자라고도 하면 다음과 같이 사용한다.
조건 ? ① : ②
조건이 참이면 ① 을 수행하고 거짓이면 ② 를 수행한다. if 문과 동일하 문법이다. 단지 한줄에 끝낼 수 있지만 알아보기 힘들기 때문에 사용을 하지 않는편이 좋다. if 문을 이용하면 다음과 같다.
if ( 조건 ) { ① } else { ②
}
[ WinApi ]
WinApi 에서 윈도우를 만드는 과정을 간단하게 살펴보자.
위와 같은 순서로 윈도우를 만든다. 위의 과정과 같이 소스를 통해 알아보자.
#include <windows.h>
WinApi 를 사용하기위해서는 위의 헤더파일을 추가해야한다. 윈도우 프로그램에서 필요한 테이터 타입, 함수 원형, 매크로 상수 등이 정의되어 있다. 콘솔 프로그램을 작성할 때 stdio.h 헤더 파일을 추가하는 것과 같다. 메인 함수를 살펴보자.
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance , LPSTR lpszCmdParam, int nCmdShow) { ... }
프로그램 시작점인 엔트리 포인트가 기존의 콘솔 프로그램의 main 함수가 아닌 WinMain 함수이다. 이 함수 앞에 사용한 APIENTRY 는 윈도우의 표준 호출 규약인 __stdcall 을 사용한다는 의미이다. 그리고 다음 4 개의 인자를 사용한다. 살펴보자.
hInstance
프로그램의 인스턴스 핸들, 프로그램 자체를 일컫는 정수값을 의미한다. 즉 자기 자신을 가리키기 위해 사용한다.
hPrevInstance
바로 앞에 실행된 현재 프로그램 인스턴스 핸들을 의미하며 없는 경우는 NULL 을 사용한다. (Win32 는 항상 NULL)
lpszCmdParam
명령행으로 입력된 프로그램 인수이다. (도스의 argv 인수와 동일)
nCmdShow
프로그램이 실행될 형태를 의미한다. (최소화, 숨김 등)
프로그램의 인스턴스 핸들, 프로그램 자체를 일컫는 정수값을 의미한다. 즉 자기 자신을 가리키기 위해 사용한다.
hPrevInstance
바로 앞에 실행된 현재 프로그램 인스턴스 핸들을 의미하며 없는 경우는 NULL 을 사용한다. (Win32 는 항상 NULL)
lpszCmdParam
명령행으로 입력된 프로그램 인수이다. (도스의 argv 인수와 동일)
nCmdShow
프로그램이 실행될 형태를 의미한다. (최소화, 숨김 등)
윈도우 클래스에 대해 알아보자. 윈도우 클래스는 구조체이며 다음과 같이 선언되어 있다.
typedef struct tagWNDCLASSA { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCSTR lpszMenuName; LPCSTR lpszClassName; } WNDCLASSA;
각각의 구조체 멤버에 대해 알아보자.
style
윈도우가 어떤 형태를 가질 것인가를 지정하는 멤버이다. 자주 사용하는 CS_HREDRAW 와 CS_VREDRAW 사용하며 이러한 값들을 OR 연산자로 연결하여 사용할 수 있다.
lpfnWndProc
윈도우의 메시지 처리 함수를 지정한다. 메시지가 발생할 때마다 이 멤버가 지정하는 함수가 호출되며 이 함수가 모든 메시지를 처리한다.
cbClsExtra, cbWndExtra
아주 특수한 목적에 사용하는 여분의 공간으로 사용하지 않을 경우는 0으로 지정한다.
hInstance
윈도우 클래스를 등록하는 프로그램의 번호이다.
hIcon, hCursor
윈도우가 사용할 마우스 커서와 아이콘을 지정한다.
hbrBackground
윈도우의 배경 색상을 지정한다. 윈도우 배경 색상을 채색할 브러시를 지정하는 멤버이다. GetStockObject 함수를 이용하여 윈도우에서 기본적으로 제공하는 브러시를 지정하거나 COLOR_WINDOW 같은 시스템 색상을 지정할 수 있다.
lpszMenuName
프로그램이 사용할 메뉴를 지정한다. 사용하지 않을 경우 NULL 을 대입한다.
lpszClassName
윈도우 클래스의 이름을 문자열로 정의한다.
윈도우가 어떤 형태를 가질 것인가를 지정하는 멤버이다. 자주 사용하는 CS_HREDRAW 와 CS_VREDRAW 사용하며 이러한 값들을 OR 연산자로 연결하여 사용할 수 있다.
lpfnWndProc
윈도우의 메시지 처리 함수를 지정한다. 메시지가 발생할 때마다 이 멤버가 지정하는 함수가 호출되며 이 함수가 모든 메시지를 처리한다.
cbClsExtra, cbWndExtra
아주 특수한 목적에 사용하는 여분의 공간으로 사용하지 않을 경우는 0으로 지정한다.
hInstance
윈도우 클래스를 등록하는 프로그램의 번호이다.
hIcon, hCursor
윈도우가 사용할 마우스 커서와 아이콘을 지정한다.
hbrBackground
윈도우의 배경 색상을 지정한다. 윈도우 배경 색상을 채색할 브러시를 지정하는 멤버이다. GetStockObject 함수를 이용하여 윈도우에서 기본적으로 제공하는 브러시를 지정하거나 COLOR_WINDOW 같은 시스템 색상을 지정할 수 있다.
lpszMenuName
프로그램이 사용할 메뉴를 지정한다. 사용하지 않을 경우 NULL 을 대입한다.
lpszClassName
윈도우 클래스의 이름을 문자열로 정의한다.
위의 윈도우 클래스의 구조체의 멤버변수에 값을 설정하여 어떠한 윈도우를 만들것인지 정의를 한다. 다음과 같이 설정할 수 있다.
// 예약 영역 (특수한 목적에 사용) 사용하지 않으면 0 WndClass.cbClsExtra = 0; WndClass.cbWndExtra = 0; // 윈도우 배경 색상 지정 WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 윈도우가 사용할 마우스 커서 지정 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); // 윈도우가 사용할 아이콘 지정 WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 윈도우 클래스를 등록하는 프로그램 번호 WndClass.hInstance = hInstance; // 윈도우의 메시지 처리 함수를 지정 WndClass.lpfnWndProc = WndProc; // 윈도우 클래스 이름을 문자열로 정의 WndClass.lpszClassName = lpszClass; // 프로그램이 사용할 메뉴 지정 WndClass.lpszMenuName = NULL; // 윈도우 스타일 정의 윈도우의 형태를 OR 연산자를 사용하여 지정 WndClass.style = CS_HREDRAW | CS_VREDRAW;
윈도우 클래스의 정의가 끝이 나면 이 윈도우를 등록을 해야한다. 등록을 하기 위해서는 다음 함수를 호출한다.
/*** 클래스 등록 ***/ RegisterClass(&WndClass); // WndClass 구조체의 번지를 전달
등록을 한 후에 비로서 윈도우를 생성한다. 다음과 같이 생성을하고 있다.
/*** 메모리상에 윈도우 생성 ***/ hWnd = CreateWindow( lpszClass, lpszClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, (HMENU)NULL, hInstance, NULL);
인자값이 상당히 많다. 하나 하나씩 살펴보자.
HWND CreateWindow ( lpClassName, lpWindowName, dwStyle, x, y,
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam )
lpClassName
생성하고자 하는 윈도우의 클래스를 지정하는 문자열을 의미한다.
lpWindowName
윈도우의 타이틀 바에 나타날 문자열을 의미한다.
dwStyle
윈도우의 형태를 지정하는 인수이다. 비트 필드값으로 OR 연산자로 연결할 수 있다.
x, y
윈도우의 위치 지정을 설정한다. CW_USEDEFAULT 는 운영체제가 자동으로 설정해 준다.
nWidth, nHeight
윈도우의 크기 지정을 설정한다. CW_USEDEFAULT 는 운영체제가 자동으로 설정해 준다.
hWndParent
부모 윈도우의 핸들을 지정한다. (없는 경우 NULL)
hMenu
메뉴 핸들을 지정한다. (사용하지 않으면 NULL)
hInstance
윈도우를 만드는 주체인 프로그램 핸들을 지정한다.
lpParam
CREATESTRUCT 구조체의 주소 여러개의 윈도우를 만들 때 윈도우 고유의 파라미터를 전달하는 특수한 목적에 사용한다. (보통은 NULL)
CreateWindow 의 리턴값은 윈도우를 대표하는 번호인 윈도우 핸들을 리턴한다.
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam )
lpClassName
생성하고자 하는 윈도우의 클래스를 지정하는 문자열을 의미한다.
lpWindowName
윈도우의 타이틀 바에 나타날 문자열을 의미한다.
dwStyle
윈도우의 형태를 지정하는 인수이다. 비트 필드값으로 OR 연산자로 연결할 수 있다.
x, y
윈도우의 위치 지정을 설정한다. CW_USEDEFAULT 는 운영체제가 자동으로 설정해 준다.
nWidth, nHeight
윈도우의 크기 지정을 설정한다. CW_USEDEFAULT 는 운영체제가 자동으로 설정해 준다.
hWndParent
부모 윈도우의 핸들을 지정한다. (없는 경우 NULL)
hMenu
메뉴 핸들을 지정한다. (사용하지 않으면 NULL)
hInstance
윈도우를 만드는 주체인 프로그램 핸들을 지정한다.
lpParam
CREATESTRUCT 구조체의 주소 여러개의 윈도우를 만들 때 윈도우 고유의 파라미터를 전달하는 특수한 목적에 사용한다. (보통은 NULL)
CreateWindow 의 리턴값은 윈도우를 대표하는 번호인 윈도우 핸들을 리턴한다.
윈도우를 생성하였다면 이제는 윈도우가 화면에 출력을 해주는 함수를 호출한다.
ShowWindow ( hWnd, nCmdShow );
hWnd 는 윈도우의 핸들이며, nCmdShow 는 윈도우 화면에 출력하는 방법을 지정하는 인자이다. 이 인자는 매크로 상수로 정의 되어 있으며 다음과 같다.
SW_HIDE
윈도우 숨김
SW_MINIMIZE
윈도우 최소화 및 비활성화
SW_RESTORE
윈도우 활성화
SW_SHOW
윈도우 활성화하여 보여줌
SW_SHOWNORMAL
윈도우 활성화하여 보여줌
윈도우 숨김
SW_MINIMIZE
윈도우 최소화 및 비활성화
SW_RESTORE
윈도우 활성화
SW_SHOW
윈도우 활성화하여 보여줌
SW_SHOWNORMAL
윈도우 활성화하여 보여줌
이렇게 윈도우를 정의하고 등록하여 메모리상에 윈도우를 만들고 이를 출력하도록 하였다. 이제는 사용자로부터의 메시지를 처리하는 부분을 살펴보자.
메시지는 사용자가 시스템의 내부적인 동작에 의해 발생된 일체의 변화에 대한 정보를 말한다. 순서를 따르지 않고 주어진 메시지에 대한 반응을 정의하는 방식을 이용하여 프로그램이 실행된다. 이렇게 윈도우 프로그램에서 메시지를 처리하는 부분을 메시지 루프라고 하며 WinMain 함수의 끝에 보통 존재한다. 그 형태는 다음과 같다.
/*** 메시지 루프 - WndProc 에 메시지를 보내줌 ***/ // 메시지 큐에서 메시지 읽어옴 WM_QUIT 면 FALSE 리턴 while( GetMessage(&Message, NULL, 0 , 0) ) { TranslateMessage(&Message); // 키보드 입력 처리 DispatchMessage(&Message); // 큐에서 꺼낸 메시지를 WndProc 함수의 iMessage 로 전달 }
3 개의 함수를 통하여 메시지를 처리한다. 하나씩 살펴보자.
BOOL GetMessage ( LPMSG lpMsg, HWND hWnd, UINT wMsgFiterMin, UINT wMsgFiterMax );
GetMessage 함수는 메시지 큐에서 메시지를 읽어들이는 역할을 한다. 메시지 큐는 시스템이나 사용자로 부터 발생된 메시지가 잠시 대기하는 일종의 메시지 임시 저장 영역이다. 메시지 큐에서 읽어왔을 때 WM_QUIT 이면 FALSE 를 리턴하고 그외에는 TRUE 를 리턴한다.
BOOL TranslateMessage ( CONST MSG *lpMsg );
키보드의 눌림 메시지가 발생할 때 문자가 입력되었다는 메시지를 만드는 역할을 한다. 즉 키보드의 A 키를 누르면 A 문자가 입력되었다는 메시지를 만든다.
LONG DispatchMessage ( CONST MSG *lpmsg );
메시지 큐에서 꺼낸 메시지를 윈도우의 메시지 처리 함수인 WndProc 로 전달한다. 이 때 WndProc 함수를 호출하는 것이 아님을 유의하자. WndProc 함수는 OS 가 호출하는 것이다.
정리를 하자면 메시지 루프에서 하는 일은 메시지 큐에서 메시지를 꺼내 메시지 처리 함수로 보내는 것이다. 이러한 메시지를 보내기 위해 MSG 라는 구조체를 사용한다. 이 구조체는 다음과 같이 정의 되어있다.
typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; } MSG;
구조체의 멤버에 대해 알아보자.
hwnd
메시지를 받을 윈도우 핸들이다.
message
어떤 종류의 메시지인가를 나타낸다. 가장 중요한 값이된다.
wParam, lParam
전달된 메시지에 대한 부가적인 정보를 가진다. 메시지별로 의미가 달라진다.
time
메시지가 발생한 시간이다.
pt
메시지가 발생했을 때의 마우스 위치이다.
메시지를 받을 윈도우 핸들이다.
message
어떤 종류의 메시지인가를 나타낸다. 가장 중요한 값이된다.
wParam, lParam
전달된 메시지에 대한 부가적인 정보를 가진다. 메시지별로 의미가 달라진다.
time
메시지가 발생한 시간이다.
pt
메시지가 발생했을 때의 마우스 위치이다.
메시지는 실제로 정수값으로 표현되며 메시지의 종류가 엄청 많다. 보통 WM_ 로 시작되는 것들이 메시지이다. 주로 자주 사용하는 메시지를 살펴보자.
WM_QUIT
프로그램을 끝낼 때 발생하는 메시지이다.
WM_LBUTTONDOWN
마우스의 좌측 버튼을 누를 경우 발생한다.
WM_CHAR
키보드로부터 문자가 입력될 때 발생한다.
WM_PAINT
화면을 다시 그려야 할 필요가 있을 때 발생한다.
WM_DESTROY
윈도우가 메모리에서 파괴될 때 발생한다.
WM_CREATE
윈도우가 처음 만들어질 때 발생한다.
프로그램을 끝낼 때 발생하는 메시지이다.
WM_LBUTTONDOWN
마우스의 좌측 버튼을 누를 경우 발생한다.
WM_CHAR
키보드로부터 문자가 입력될 때 발생한다.
WM_PAINT
화면을 다시 그려야 할 필요가 있을 때 발생한다.
WM_DESTROY
윈도우가 메모리에서 파괴될 때 발생한다.
WM_CREATE
윈도우가 처음 만들어질 때 발생한다.
메시지를 WndProc 함수에 전달한다. 이 전달받은 메시지를 OS 에 의해 호출되면 WndProc 함수가 처리를 한다. 이렇게 운영체제에 의해 호출되는 응용 프로그램 내의 함수를 콜백 함수라고 한다. 콜백 함수를 살펴보자.
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { /* 고정 형식 */ switch(iMessage) // 운영체제로부터 들어온 메시지에 대한 처리 { case WM_DESTROY : PostQuitMessage(0); // WM_QUIT 메시지를 보냄 return 0; } // switch 문에서 처리하지 않은 메시지를 처리 return (DefWindowProc(hWnd, iMessage, wParam, lParam)); }
WndProc 함수의 인자를 살펴보면 wParam 과 lParam 은 iMessage 의 메시지에 따른 부가적인 정보를 가진다. 메시지가 마우스 왼쪽 버튼을 눌렀다면 위의 두 인자는 화면의 어디쯤에서 버튼이 눌러졌는가의 추가 정보를 이 두 인자에 전달된다. 따라서 메시지에 따라서 값이 달라진다.
콜백 함수의 본체에는 기본적인 형태는 다음과 같다.
switch(iMessage) { case Msg1: 처리1; return 0; case Msg2: 처리2; return 0; case Msg3: 처리3; return 0; default: return DefWindowProc(...); }
메시지에 따라 어떻게 처리할 것인지 정의하고 처리가 끝이나면 0 을 리턴시킨다. 제일 끝에 있는 DefWindowProc 함수는 WndProc 에서 처리하지 않은 나머지 메시지에 관한 처리를 한다. 전체적인 흐름도는 다음과 같다.
728x90
'코스웨어 > 11년 내장형하드웨어' 카테고리의 다른 글
[내장형]이상만_2011년 8월 30일_일일보고서 (9) | 2011.08.30 |
---|---|
[내장형]윤병도_2011년 8월 26일_일일보고서 (11) | 2011.08.26 |
[내장형]이영진_2011년 8월 24일_일일보고서 (10) | 2011.08.24 |
[내장형]백길남_2011년 8월 23일_일일보고서 (10) | 2011.08.23 |
[내장형]한원우_8월 19일 일일보고서 (11) | 2011.08.21 |
[내장형]이동현_08월18일_일일보고서 (8) | 2011.08.19 |
[MV] 21세기 모노리스 - 015B (0) | 2011.08.18 |
8월17일 일일보고서 - 김정우 (10) | 2011.08.17 |