[참조: http://idrose1025.egloos.com/2628732]
[그림 참조: http://alghost.tistory.com/22
]

Doxygen 주석 사용법 


Doxgen은 많이 사용하고 있고 사용법도 간단하지만 가끔 어떤 식으로 주석을 해야하는지 까먹습니다. 
아래와 같은 형식이 가장 마음에 들고 좋은 것 같습니다.

\brief 나 \return 등이 보여주는 항목 이외에 다른 항목을 쓰고 싶다면 \par 명령어를 사용하면 된다.

/** \brief

        현재 시간을 얻는다.

    \remarks

        ST_TIME 구조체 형식으로 현재 시간을 얻는다.

    \par 요구사항

        time.h 선언이 필요하다.

    \return

        성공시 0을 반환한다. 에러가 발생하면 -1을 반환한다.

    \author

        이상호

**/




Blogger: moltak.net 

'Programming > 이것저것' 카테고리의 다른 글

[펌] valgrind 를 이용한 메모리 관리  (0) 2011.03.15
Doxygen - 작성중  (0) 2011.03.08
_Crt Debug Functions  (0) 2010.07.23
typeid 2  (1) 2010.05.25
세그먼트 레지스터  (0) 2010.05.01

메모리 릭을 해결하기 위해 문서를 찾던중
[펌: http://adnoctum.tistory.com/555]


   C/C++ 의 골치거리 중 하나인 메모리 문제를 조금이나마 쉽게 해결하고자 나와 있는 프로그램 중 사용이 편리하고 open-source 인 valgrind 에 대해 알아 보자. valgrid는 leak 이 생긴/생길 가능성이 있는 코드의 부분을 찾아 주고, 잘못된 메모리 접근을 알려 주는 등의 기능을 한다. 이것은 특히 다른 사람이 작성한 소스 코드를 이용해야 할 때 유용한데, 코드의 전체적인 내용을 파악하지 못한 상태에서도 메모리 검사를 할 수 있기 때문이다. 나의 경우도 지금 남의 코드를 가져 와서 하고 있기 때문에, 일단 실행 시간 에러는 없이 실행되는 것을 확인했지만 정말로 문제없이 돌아가는 것인지 확인하기 위해 오랜만에 valgrind를 꺼내 들었다. 실제 사용 예는 다음과 같다. 

[adnoctum@bioism src]$ g++ ~/LJSLibrary/library/util.o cluster.o cluster.cpp -o c -g
[adnoctum@bioism src]$ valgrind --leak-check=full --log-file-exactly=memcheck.txt -v --error-limit=no ./c test.txt

첫 번째 줄은 test 로 사용할 프로그램을 컴파일 하는 부분. -g 옵션을 줘야 함수 이름과 정확한 코드의 위치(줄 수)가 나와서 보기 쉽다. valgrind 의 option 은 적당히 준다. valgrind --help 에 잘 나와 있다. 사용법은 아주 간단하다. 

valgrind [options] executible

을 따른다. option 은 적당히 주면 되고, executible 은 원래 프로그램을 실행시키는 것과 같다. 즉, 위의 경우 실행 파일이 c 이고 입력으로 test.txt 파일을 넣게 되어 있다. 그래서 이 프로그램을 실행시키려면 원래는

./c test.txt

를 하게 되는데, 바로 이 부분을 valgrind 의 입력으로 넣으면 되는 것이다. 그래서 위의 예에서 2 번째 줄처럼 된다. 

-v 옵션을 주면 내용이 많기 때문에 좀 복잡할 수 있는데, 차근차근 따라가면 별로 어렵지 않다. 결과 파일이 매우 길기 때문에 부분부분 가져와서 왜 문제가 생겼는지를 소스 코드와 비교해 보자. 

일단 가장 아래부분 근처에 보면 다음과 같은 요약이 있다. 

==9581== IN SUMMARY: 9 errors from 9 contexts (suppressed: 15 from 1)
==9581==
==9581== malloc/free: in use at exit: 0 bytes in 0 blocks.
==9581== malloc/free: 4,997 allocs, 4,997 frees, 243,658 bytes allocated.
==9581==
==9581== All heap blocks were freed -- no leaks are possible.

일단 메모리 누수는 없는 것으로 보인다. 제일 앞에 쓰여 있는 숫자는 PID 이다. 만약 --PID-- 이면 정보를 보여 주는 것이고, 만약 == PID == 라면 에러가 난 부분을 보여 주는 것으므로 참고한다. 그럼 이젠 제일 앞부분부터 살펴 보자. 

==9581== Invalid read of size 8
==9581==    at 0x805DC0F: main (cluster.cpp:149)
==9581==  Address 0x4096238 is 8 bytes after a block of size 224 alloc'd
==9581==    at 0x40053C0: malloc (vg_replace_malloc.c:149)
==9581==    by 0x805B067: treecluster (cluster.c:3656)
==9581==    by 0x805DB52: main (cluster.cpp:134)

내용인 즉, 8 바이트를 읽었는데, 원래는 읽으면 안되는 것이었다는 것이다. 직접적인 줄은 cluster.cpp 파일의 149 번째 줄이고, 밑에 call stack 이 나와 있다. 그래서, cluster.cpp 파일의 149 번째 줄 근처로 가보면, 


134   Node* tree = treecluster(nRow, nCol, data, mask, weight, transpose, metric, method, NULL);
135
136   int nNodes = 0;
137   if(transpose != 0){
138           nNodes = nCol;
139   }
140   else{
141           nNodes = nRow;
142   }
143   double* order = (transpose==0) ? new double[nCol] : new double[nRow];
144   for(i = 0; i<nNodes; i++) order[i] = i;
145   if (metric=='e' || metric=='b')
146   /* Scale all distances such that they are between 0 and 1 */
147   { double scale = 0.0;
148     for (i = 0; i < nNodes; i++)
149       if (tree[i].distance > scale) scale = tree[i].distance;
150     if (scale) for (i = 0; i < nNodes; i++) tree[i].distance /= scale;
151   }

위 코드인데, 149번째 줄에서는 tree를 접근하고 있다. 위에서 8 바이트라 했으므로, 아마도 double 형 요소인 distance 를 말하는 것일테고, 위 코드와 잘 맞는다. 그럼 왜 읽지 말아야 하는 부분을 읽었다고 했을까? 조건(148라인)을 보면 for 문에서 i 를 nNodes 까지 돌리고 있다. 즉, nNodes-1번까지 돌테고, 일반적으로 잘 맞는듯이 보인다. 그런데, 134 번째 줄을 보니 tree 는 treecluster 라는 함수의 반환값이고, nNodes 는 137번째 줄에서 적당히 설정되고 있다. 이 부분은 좀 이 예 의존적이긴 한데, 어쨌든 어떻게 풀어 나가는지에 대한 흐름만 따라가 보자. 위 코드는 Cluster 3.0 의 소스 코드를 가져 온 것인데, 메뉴얼에 보면 hierarchial clustering 결과 반환되는 노드 수는 원래의 item 보다 한 개 적다고 한다. 즉, 지금 nCol을 기준으로 clustering 을 하면 반환되는 노드 수는 nCol - 1 이어야 하는 것이다. 따라서 tree의 index 는 nCol - 2 까지만 가야 하겠지. 따라서 위의 코드 중에는 138, 141 번에서 - 1 을 추가해 주어야 한다. 이런 에러는 중요하다. 왜냐 하면, 이렇게 읽지 말아야 하는 곳을 읽을 경우 에러가 났다 안났다 하기 때문에 잡기 좀 어렵기 때문이다. 매번 죽으면 상관이 없는데, 같은 release mode라 해도 어떤 때는 잘 되고 어떤 때는 죽는 경우는 디버깅 하기 참 어려운데, 이렇게 접근하면 안되는 곳을 접근하는 경우 자주 그렇게 된다. 언뜻 봐선 에러 없이 끝난 것 같아도 실은 언제 터질지 모르는 고장난 시한 폭탄을 갖고 있는 격. 결국, 데모할 때 터지겠지, >.<"" 어쨌든, 이 부분은 이렇게 해결하고, 다음으로 넘어 가면, 

==9649== Mismatched free() / delete / delete []
==9649==    at 0x4004973: operator delete[](void*) (vg_replace_malloc.c:256)
==9649==    by 0x805E268: main (cluster.cpp:235)
==9649==  Address 0x4096E98 is 0 bytes inside a block of size 120 alloc'd
==9649==    at 0x40046FF: calloc (vg_replace_malloc.c:279)
==9649==    by 0x805D164: TreeSort(char, int, double const*, double const*, int const*, Node*, double**) (cluster.cpp:25)
==9649==    by 0x805DFF9: main (cluster.cpp:215)

malloc/free, new/delete, new []/delete [], 에 대한 대응이 잘못되었다는 얘기다. 실제로 235번째 줄은 delete [] neworder; 로 되어 있는데, 소스 코드를 보면 neworder 는 calloc 으로 할당이 된다. 따라서 이 부분에 맞게 free로 바꿔 주면 문제 해결. 원래의 코드가 ANSI  C 로 되어 있고 난 C++을 써버릇해서 이런 문제가 생겼다. 

   초기화되지 않은 변수에 의존해서 jmp 나 move, 즉 if 문 안쪽에 초기화되지 않은 변수에 의해 비교, 할당이 일어날 수 있다는 경고도 있는데 그것은 생략한다. 

'Programming > 이것저것' 카테고리의 다른 글

Doxgen 주석  (0) 2011.05.02
Doxygen - 작성중  (0) 2011.03.08
_Crt Debug Functions  (0) 2010.07.23
typeid 2  (1) 2010.05.25
세그먼트 레지스터  (0) 2010.05.01
1.파일

/**

@file main.cpp

@date 2009/04/25

@author 홍길동(hong@aaa.com)

@brief 프로그램의 구동

*/

 

2.클래스

해당 클래스 선언부 위에 위치한다.

/**

@class main.cpp

@date 2009/04/25

@author 홍길동(hong@aaa.com)

@brief 프로그램의 구동

@warning 주의 사항이 있으면 이 곳에 입력한다.

*/

 

3.함수 설명

해당 함수 위에 위치한다.

/**

@return char * : 이름

@param strPersonNum : 주민등록번호

@brief 해당 주민등록번호의 이름을 가져온다

@warning 주민등록번호는 - 없이 입력한다.

*/

 

4. 간략설명

 해당 라인의 뒤에 위치한다.

unsigned logn nAssetIP;     ///< 자산 아이피

또는

unsigned logn nAssetIP;     /**< 자산 아이피 */

 

5.주석 내 사용되는 item 들

 @breif        간략한 설명을 쓴다.
 @remarks   자세한 설명을 쓴다.
 @file          파일 이름을 구별할때.
 @return      함수의 리턴값 나타낼때.
 @author     작성자 이름을 나타낼때
 @date        작성날짜를 나타낼때.
 @param      함수 파라메터를 나타낼때
 @see         참고할 함수나 페이지를 지정한다.
 @todo        해야할일들에 대한 기술, 전체 항목의 @todo에 대한 리스트가 생성됩니다
 @bug         버그에 대한 기술, 전체 항목의 @bug에 대해서 따로 리스트가 생성됩니다.
 @code       중요 코드를 설명할때 시작 지점 가리킨다.
 @endcode  중요 코드 설명할때 종료 지점 가리킨다.
 @exeception exception처리에 대한 설명
 @mainpage
 @section


 @throw: throw하는 객체나 변수등에 대한 설명

'Programming > 이것저것' 카테고리의 다른 글

Doxgen 주석  (0) 2011.05.02
[펌] valgrind 를 이용한 메모리 관리  (0) 2011.03.15
_Crt Debug Functions  (0) 2010.07.23
typeid 2  (1) 2010.05.25
세그먼트 레지스터  (0) 2010.05.01
디모그 모드에서 프로그램을 종료하면 메모리 릭이 발생하는 경우가 있다.
그때 vs의 output 창에 아래와 같은 메시지가 나온다.


Detected memory leaks!
Dumping objects ->
{130} normal block at 0x004866F0, 712 bytes long.
 Data: <xA  8bH       ' > 78 41 03 10 38 62 48 00 01 CD CD CD 02 00 27 11 


이 메모리 릭을 어떻게 찾아야 하나 막막했다.
그런데 CRT에는 릭을 감지하는 debug function들이 있다. 이 함수들을 사용하면 메모리 릭이 있는 위치를 찾을 수 있다.

한가지 덧 붙이자면 릭 메시지 안의 {130} 의 의미는 프로그램에서 몇번째로 할당 받은 영역이라는 것이다. 위 메시지는 130번째로 할당받았다는 의미다.

메모리 릭을 추적하기 위해 Crt 함수를 사용하면 된다. Crt 함수를 사용하기 위해서는 다음 순서를 반드시 따라야 한다.

#include <stdlib.h>
#include <crtdbg.h>

_CrtDumpMemoryLeaks(); // 이 함수는 output 창에 메모리 릭 정보를 출력시킨다.
_CrtSetBreakAlloc( 130 ); // 이 함수는 130번째 메모리를 할당하려고 할 때 프로그램을 break 시켜준다.
_crtBreakAlloc = 130; // 이렇게 사용할 수 도 있다.

_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
이 문은 프로그램이 종료될 때 자동으로 _CrtDumpMemoryLeaks를 호출한다.


_CrtSetDbgFlag 함수는 다섯개의 Flag 가 있다.
_CRTDBG_ALLOC_MEM_DF : 디폴트로 켜져 있으며, 디버그 버전에서 모든 메모리 할당이 일어날 때마다 추적 가능하도록 특별한 기능을 추가해 준다. 이 플래그가 켜져 있어야 메모리 누수를 안전하게 검사할 수 있다.

_CRTDBG_DELAY_FREE_MEM_DF : delete, free 등으로 삭제되어도 바로 삭제되지 않고, CRT의 메모리 관리소에 남아 있다가 프로그램 종료시에 완전히 삭제된다.

_CRTDBG_CHECK_ALWAYS_DF : 모든 메모리관련 연산에서 _CrtCheckMemory를 호출한다.

_CRTDBG_CHECK_CRT_DF : CRT가 내부적으로 할당한 블록도 메모리를 체크할 때 포함한다. 일반적으로는 CRT가 할당한 블록은 메모리 체크에서 제외된다. 일반적으로 사용하지 않는다.

_CRTDBG_LEAK_CHECK_DF : 프로그램이 완전히 종료되기 직전에 아직 해체되지 않는 메모리가 있는지 검사한다. 프로그램의 종료 포인트가 여러운데 있는 경우에 사용하면 일일이 _CrtDumpMemoryLeaks 메소드를 호출하지 않아도 자동적으로 메모리 누수를 검사할 수 있게 된다.

이중 _CRTDBG_ALLOC_MEM_DF를 제외하고는 모두 디폴트로 꺼져 있다. 그러므로 다음과 같이 메모리 검사 기능을 켜도록 해야한다. 
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
// MFC의 경우는 위의 옵션이 활성화 되어 있다.


Bloger : moltak.net

'Programming > 이것저것' 카테고리의 다른 글

[펌] valgrind 를 이용한 메모리 관리  (0) 2011.03.15
Doxygen - 작성중  (0) 2011.03.08
typeid 2  (1) 2010.05.25
세그먼트 레지스터  (0) 2010.05.01
x86 Register  (0) 2010.04.30
예전에 typeid 포스팅을 한 적이 있습니다. (http://moltak.net/search/typeid) 참조
열심히 플젝을 하던 중 원하는 결과값이 안나와서 왜 그런가 하고 한시간 가량 삽질 끝에 알아 냈네요.;;

위 포스팅을 보시면 typeid( type ).name()을 통해서 type의 이름을 얻어 오는 것이 있습니다.
.name() 함수가 현재 타입을 알려주는 역할을 하죠.
저는 아래와 같이 사용하고 있었습니다.


다들 아시겠지만 우리가 원하는 결과는?? 젤 아래 결과가 당연히 Sub가 나와야 맞습니다.
하지만 그렇지 않더군요. 결과를 먼저 볼까요?

위와 같이 전부 Super 클래스가 나왔네요?? 왜 그런걸까요? 제가 잘 못했겠죠?? 아직 확실한 이유는 모르지만 결과를 올바르게 바꾸는 방법은 알아 냈습니다.





바로 위 소스와 같이 사용하지 않는 하나의 함수를 집어 넣는 것입니다. C++은 상속을 받았을 때, 가상함수 테이블이 생기게 됩니다. typeid는 클래스의 경우 가상함수 테이블을 보고 type을 결정짓지 않나 생각이 드네요.
정확히 아시는 분은 알려주세요. ㅠㅠ 기다리겠습니다. ㅋㅋ


Bloger: moltak.net


'Programming > 이것저것' 카테고리의 다른 글

Doxygen - 작성중  (0) 2011.03.08
_Crt Debug Functions  (0) 2010.07.23
세그먼트 레지스터  (0) 2010.05.01
x86 Register  (0) 2010.04.30
어셈블리어 점프 명령어  (0) 2010.04.29

오늘은 메모리 구조에서 가장 복잡하다고 느끼는 세그먼테이션에 대해서 정리하겠습니다.

x86에서는 segmentation과 paging 기법을 이용하여 [가상 메모리] 를 만들고 프로그램들을 실행시키게 됩니다.

그림 1 Physical Address 변환 과정

 

가상 메모리는 세그먼테이션 과정을 거치고 페이징 과정을 거쳐서 실제 메모리가 나오게됩니다.

이때 세그먼테이션에는 Selector와 Offset이 들어가게 되는데 Selector는 이 챕터의 제목인 세그먼트 레지스터를 말합니다. Offset은 가상주소를 말합니다.

 

그냥 말로 서술하면 보기 힘드니 숫자를 붙여서 설명을 해 드리겠습니다.

 

세그먼테이션 과정

  1. 가상주소를 물리 주소로 바꾸려면 Selector(세그먼트 레지스터)와 Offset(가상주소)이 필요합니다.
  2. Selector는 16bit 이며 Descriptor Table의 Index를 가리킵니다. (그림 참조)
  3. Selector(세그먼트 레지스터)는 Descriptor table의 Segment Descriptor(그림 참조)를 가리킵니다.
  4. Segment Descriptor의 Base 주소와 가상주소를 합쳐서 선형 주소를 만들어 냅니다.

 

세그먼트 디스크립터 안의 내용은 굳이 설명하지 않아도 될 것 같네요. 다만 Base Address 0-15만 알면 될 것 같습니다. Base Address 필드는 실제 세그먼트를 통해 메모리에 접근할 때 더하는 값입니다. 아까 세그먼트 디스크립터의 Base주소와 가상주소를 더해서 32bit 선형 주소를 만든다고 했었죠? 그때 사용 되는 것입니다.

 

이제까지 저는 세그먼트 레지스터가 16bit라고 설명을 했지만 사실 80bit 입니다. 나머지 64bit은 왜 설명 안 했냐? 하신다면 했습니다. 위에서 말한 세그먼트 디스크립터가 바로 세그먼트 레지스터의 안 보이는 나머지 64bit입니다. 왜 80bit으로 만들었는지 잘 모르겠지만 많이 추측 하는 것은 세그먼트 레지스터는 자주 사용하고 자주 사용한다면 속도가 빠른 레지스터에 올리는 것이 더 낫다고 생각됩니다.

 

이젠 세그먼트 레지스터를 직접 보도록 하겠습니다. Ollydbg와 Windbg를 사용하겠습니다.

Ollydbg에서 열면 6개의 세그먼트 레지스터를 볼 수 있습니다. x86은 6개의 세그먼트 레지스터가 있습니다. 그 중 노란색으로 표시된 FS 레지스터를 보겠습니다.

FS는 Selector로 동작되며 INDEX, TI, RPL(그림 참조)필드로 이루어져 있는 것을 알 수 있습니다.

그래서 이진수로 표현하면 0000 0000 00111 0 11 가 나옵니다. 앞에 13비트는 테이블에서의 세그먼트 디스크립터 위치고 그 다음 1 비트는 GDT인지 LDT인지(인터넷 참고)를 나타내며 다음 2비트는 권한(인터넷 참고)을 나타냅니다. 중요한 것은 7번째를 가리키고 있다는 것입니다.

 

위 그림을 보시면 선택되어 있는 부분이 FS레지스터가 가리키는 세그먼트 디스크립터입니다. Ollydbg에 나온 값이랑 똑같네요.

 

 

여기까지 해서 세그먼트 레지스터와 선형 주소를 만드는 것을 보았는데요. 생각보다 어렵다고 느끼실 수도 있습니다. 하지만 조금만 공부하시고 더 자료를 찾아 보시면 정리를 완벽히 하실 수 있을 겁니다.

그럼 모두 즐공 하세요.

 

 

Bloger: moltak.net

'Programming > 이것저것' 카테고리의 다른 글

_Crt Debug Functions  (0) 2010.07.23
typeid 2  (1) 2010.05.25
x86 Register  (0) 2010.04.30
어셈블리어 점프 명령어  (0) 2010.04.29
Symbol  (0) 2010.04.24

IA 32(x86) CPU는 크게 5종류의 레지스터가 있습니다.

범용 레지스터, 인덱스 레지스터, 포인터 레지스터, 부동 소수점 레지스터, 플래그 레지스터가 그것이며 각각 사용용도가 모두 다릅니다.

레지스터들 앞에 붙어있는 E는 Extended의 약자로서 현재 사용되는 x86 architecture는 80386에서 점차 발전해 나갔습니다.

그래서 현재 많이 사용되는 Pentium 이나 Core 2DUO 같은 프로세서들도 80386과 거의 비슷합니다. 물론 엄~~청 나게 발전 되었지만요. 

종류

이름

설명

범용

EAX

곱셈과 나눗셈 명령에서 자동으로 사용되고 함수의 리턴값이 저장되는 용도로 사용된다.

EBX

ESI EDI 결합하여 인덱스에 사용된다.

ECX

반복 명령어 사용시 카운터로 사용된다. ECX 레지스터에 반복할 횟수를 지정해 놓고 반복 작업을 수행한다.

EDX

EAX 같이 쓰이며 부호 확장 명령 등에 쓰인다.

인덱스

ESI

데이터 복사나 조작시 Source Data 주소가 저장된다. ESI 레지스터가 가리키는 주소의 데이터를 EDI 레지스터가 가리키는 주소로 복사하는 용도로 많이 사용된다.

EDI

복사 작업시 Destination 주소가 저장된다. 주로 ESI 레지스터가 가리키는 주소의 데이터가 복사된다.

포인터

EIP

다음에 실행해야 명령어가 존재하는 메모리 주소가 저장된다. 현재 명령어를 실행 완료한 후에 EIP 레지스터에 저장되어 있는 주소에 위치한 명령어를 실행하게 된다. 실행 EIP 레지스터는 다음 실행해야 명령어가 존재하는 주소의 값이 저장된다.

EBP

하나의 스택 프레임의 시작 지점 주소가 저장된다. 현재 사용되는 스택 프레임이 소멸되지 않는 동안 EBP 값은 변하지 않는다. 현재의 스택 프레임이 소멸되면 이전에 사용되던 스택

프레임을 가리키게 된다.

ESP

하나의 스택 프레임의 지점 주소가 저장된다. PUSH, POP 명령어에 따라서 ESP 값이 4byte 변한다.

부동

소수점

ST(0)

부동 소수 연산에 사용되는 레지스터

ST(1)

ST(2)

ST(3)

ST(4)

ST(5)

ST(6)

ST(7)

플래그

Eflag

OF

Overflow: 산술 연산 상위(가장 왼쪽) 비트의 overflow 나타냄

DF

Direction: 스트링(문자) 데이터를 이동시키거나 비교할 왼쪽 또는 오른쪽의 방향 결정

IF

Interrupt: 키보드 입력과 같은 외부 인터럽트가 처리되어야 하는지 또는 무시되어야 하는지를 나타낸다.

TF

Trap: 단일 단계 모드(single-step mode) 프로세서 연산을 허용한다. 디버거 프로그램은 TF 플래그를 설정해서, 사용자가 번에 하나씩 명령어를 실행시키고, 레지스터와 메모리 상에서 영향을 조사할 있게 한다.

SF

Sign: 산술 연산의 결과 값에 대한 부호를 나타낸다. (0=양수, 1=음수)

ZF

Zero: 산술이나 비교 연산의 결과를 나타낸다. (0= 결과 값이 0 아님, 1= 결과 값이 0)

AF

Auxiliary carry: 특수화된 산술에서 사용되며, 산술 연산에서 비트 3에서 비트 4로의 캐리를 포함한다.

PF

Parity: 연산 겨로가 1비트들의 개수를 나타낸다. 개수가 짝수인 경우 짝수 패리티(even parity) 부르며, 홀수인 경우 홀수 패리티(odd parity) 한다.

CF

Carry: 산술 연산 상위 비트의 캐리를 포함한다. 또한 비트 자리이동(shift) 또는 비트 회전(rotate) 연산 가장 마지막의 비트 내용을 포함한다.

  

'Programming > 이것저것' 카테고리의 다른 글

typeid 2  (1) 2010.05.25
세그먼트 레지스터  (0) 2010.05.01
어셈블리어 점프 명령어  (0) 2010.04.29
Symbol  (0) 2010.04.24
IL Code에 심볼 정보가 포함되는 이유  (0) 2010.04.24

참고 : http://blog.naver.com/saint_05

리버싱을 하다보면 조건 점프 명령이 많이 나와서 한번 올려봅니다.

외울 필요는 없구요 그냥 필요할 때 보는 정도로 사용하시면 될 것 같습니다.

어셈명령어

의미

점프 조건

(레지스터상태)

JA

결과가 1보다 클 경우 점프

CF=0 and ZF=0

JAE

결과가 1보다 크거나 같을 경우 점프

CF=0

JB

결과가 1보다 작을 경우 점프

CF=1

JBE

결과가 1보다 작거나 같을 경우 점프

CF=1 or ZF=1

JC

캐리 플래그가 1일 경우 점프

CF=1

JCXZ

CX가 0일 경우 점프

CX=0

JE

결과가 같을 경우 점프

ZF=1

JECXZ

ECX가 0일 경우 점프

ECX=0

JG

결과가 클 경우 점프(signed)

ZF=0 and SF=OF

JGE

결과가 크거나 같을 경우 점프 (signed)

SF=OF

JL

결과가 작을 경우 점프(signed)

SF != OF

JLE

결과가 작거나 같을 경우 점프 (signed)

ZF=1 or SF != OF

JMP

점프

없음

JNA

결과가 작을 경우 점프

CF=1 or ZF=1

JNAE

결과가 작거나 같을 경우 점프

CF=1

JNB

결과가 클 경우 점프

CF=0

JNBE

결과가 크거나 같을 경우 점프

CF=0 and ZF=0

JNC

캐리 플래그가 0일 경우 점프

CF=0

JNE

결과가 클 경우 점프

ZF=0

JNG

결과가 작을 경우 점프(signed)

ZF=1 or SF != OF

JNGE

결과가 작거나 같을 경우 점프(signed)

SF != OF

JNL

결과가 클 경우 점프(signed)

SF=OF

JNLE

결과가 크거나 같을 경우 점프(signed)

ZF=0 and SF=OF

JNO

오버 플로우 하지 않으면 점프(signed)

OF=0

JNP

패리티 플래그가 0일 때 점프

 

PF=0

JNS

결과가 Signed 가 아닐 때 점프(signed)

SF=0

JNZ

결과가 0 이 아닐 때 점프

ZF=0

JO

오버 플로우 일 경우 점프(signed)

OF=1

JP

패리티 플래그가 1일 때 점프

PF=1

JPE

패리티가 같을 때 점프

PF=1

JPO

패리티가 홀수 이면 점프

PF=0

JS

Sign플래그가 1일 때 점프

SF=1

JZ

0이면 점프

ZF=1

좀 더 자세히 알고 싶으시면 http://asmlove.co.kr 에서 확인 해 보시길 바랍니다.

'Programming > 이것저것' 카테고리의 다른 글

세그먼트 레지스터  (0) 2010.05.01
x86 Register  (0) 2010.04.30
Symbol  (0) 2010.04.24
IL Code에 심볼 정보가 포함되는 이유  (0) 2010.04.24
초기화 하지 않은 메모리  (0) 2010.04.16

사실 저도 심볼 심볼만 하고 있었지 이 녀석이 무엇인지 어떤 역할을 하는지 잘 몰랐습니다.

저는 친절한 임베디드 시스템 블로그(http://recipes.egloos.com)를 참고 했습니다.

(개인적으로 굉장히 좋은 사이트라 생각합니다... 못 믿으시겠다면 어서 방문을 ㄱㄱㄱ)

 

http://recipes.egloos.com/5009181 여기를 보면 심볼에 대한 정보가 굉장히 잘 나와있습니다.

심볼이란 Linker가 쓰는 기본 단위로써, Link를 한 후 에는 자신만의 주소를 갖게 되는 특별한 단위를 말한다. 

(이 부분이 젤 중요합니다.)

위에 진하게 되어 있는 곳을 보죠. 그 중 빨간색이 가장 중요한데요. "자신만의 주소를 갖게 된다" 이 부분 입니다.. 

우리가 C로 프로그램을 짜고 디버깅을 할 때 생각해 보죠. 우리는 그 변수에 할당된 값들을 볼 수 있습니다.

 이 때 이것들의 주소가 없다면? 당연히 볼 수 없겠죠?? 하지만… 우리는 모든 변수들의 값들을 볼 수 있습니다. 

왜냐? 주소를 갖고 있기 때문입니다. 지역변수 들은 비록 EBP, ESP로 할당된 스택 프레임 안에 들어 있지만. 

일단은 주소를 갖고 있죠? 근데 이것들은 심볼이라는 것이 없습니다. 위에서 보면 "자신만의 주소"를 갖게 되는 특별한 단위라고 했는데 왜 심볼이 없냐 하면… 이 지역변수 주소는 "자신만의 주소"는 아니죠? 스택 프레임은 각 함수마다 할당되었다 사라졌다 합니다. 그 주소는 여러 변수에 의해서 계속 쓰이게 됩니다. 그래서 지역 변수는 "심볼이 없다"라고 볼 수 있겠네요.


이 분은 Symbol을 Global이라고 부르십니다(왠지 교주 찬양하는 것 같네요 -_ -;;). Global 은 프로그램이 시작하고 끝날 때까지 없어지지 않는 것들을 말하죠? 거기에 해당되는 것들이 뭐뭐 있을 까요? 함수, 전역변수, static 변수가 있죠? 위에서 말한 것 처럼 자신만의 주소를 갖게 되는 것도 이런 Global 밖에 없습니다. 나머지는 전부 stack, heap이죠…. 할당 되고 해제 되는…


자자 계속 할게요. Symbol의 이름은 그 Symbol이 갖는 메모리 영역의 시작 주소를 가리키는 Linker만의 pointer라고 하네요. 우리가 디버깅 할 때 VS에서는 자동으로 pdb 파일이 생성되죠?


(모른신다고 하면 안됩니다. 여기 증거가ㅋㅋ)


이때도 symbol의 이름이 사용된다고 합니다. 또한 우리가 C, CPP 파일을 컴파일 하면 object file(이 녀석은 소스 파일마다 생성됩니다.)


이 생성되는데 이 안에는 Linker를 위해서 symbol table을 놔둔다고 합니다. 여기 안에는 source code에 의해서 참조되는 symbol들의 이름과 위치 정보가 들어 있으며, 다른 파일에 정의되어 있는 symbol정보를 쓸 경우에는 그 정보가 해당 file에 없기 때문에 그 object 파일 안에 있는 symbol table은 완전하지 못하다고 하네요. 이런 불완전한 symbol들은 linker에 의해서 처리하여 다른 파일에 있는 symbol을 연결하여 사용할 수 있도록 만든다고 합니다. 이 symbol 정보들은 메모리에 올라오는 것이 아니며…. 오직 linker만이 이 정보들을 쓴다고 하네요. 그리고 binary(윈도우는 PE, 리눅스는 elf)로 만들어 질 때 이 symbol들을 주소로 모두 변환한다고 합니다. (네 그래서 native code안에는 symbol 정보가 없습니다.)

 

여기까지가 제가 공부한 내용이네요. 요약해서 뭔 말인가 하면. 이 symbol정보들은 global 한 정보들을 말하며 실제 실행 파일 안에는 들어가 있지 않다. 왜냐면 linker만 사용하기 때문에 그리고 실행파일로 만들 때 object file 안의 symbol 들을 모두 주소로 변환하니깐. 이제 좀 이해가 되기 시작하네요…(감사합니다 히언님ㅋ)

 

Bloger: moltak.net

'Programming > 이것저것' 카테고리의 다른 글

x86 Register  (0) 2010.04.30
어셈블리어 점프 명령어  (0) 2010.04.29
IL Code에 심볼 정보가 포함되는 이유  (0) 2010.04.24
초기화 하지 않은 메모리  (0) 2010.04.16
[Design Pattern] Singleton Pattern  (2) 2010.04.16

이제 심볼이란 것이 무엇인지 정확이 알았으니…

IL Code에 왜 심볼 정보가 포함되는지 알아 봐야죠??

저번 시간에 Native Code에 왜 심볼정보가 포함되지 않는지를 봤었죠??

(못봤으면 참고: http://moltak.net/entry/Symbol이란)

간단히 설명하자면 심볼은 linker가 쓰는 것으로 binary가 생성되면서 심볼정보는 다 지운다고 했었습니다.

(정확히 말하면 모두 주소로 변환)

그래서 C언어를 어셈으로 보면 알아 먹기가 힘들었죠.

하지만 IL Code는 안에 심볼정보가 포함되어 있기 때문에 원래 짠 코드 그대로 볼 수 있습니다.

 

(참고: 쩔철이네 블로그)

 

처음 심볼이 뭔지 제대로 알지도 못할 때 진 MVP인 철에게 물었습니다.

어째서 IL코드에는 심볼정보가 포함되는 거야? 하구요. 철은 범용적인 것 보다는 .NET에 특화된 말을 했습니다.

(철이 말: 즉.. .Net에서는 이런 "언어간 상호 운영성"을 위해서 CLS가 존재하고, CLR은 이에 기인하여 생성된 IL코드를 기반으로 명령을 수행한다는 것이지요..

   

여기서 서로 다른 언어에서 동일한 Type이나 기능이지만 언어간에 서로 다른 형태의 Keyword를 사용할 수 있기 때문에..

IL코드의 생성이 필요하게 되었고, 이렇게 서로 다른 Keyword를 사용하는 언어간 동일한 동작을 보장하기 위해 어떤 동일한 명령으로 변환시키기 위해서 "IL코드에 심볼들이 포함 될 수 밖에 없었다."라는 것이 제가 내린 결론입니다.)

 

네…. 맞는 말인 것 같지만… 너무 복잡하네요. 쉽게 풀어서 설명해보죠.

 

다음 내용들은 ezbeat(http://ezbeat.tistory.com/182)블로그를 참고했습니다.

(모르는게 나오면 지인들의 힘을 빌리는 것이 참…. 편하고 좋더군요 ㅋㅋ)

 

자자 이제 정리해보죠. 사실 참 쉬운 것들이었습니다.

제가 자주 사용하는 C, C++은 Native Code를 생성해 내게 됩니다. 이게 뭐냐 하면 하드웨어에 종속되어 있는 코드입니다. 바로 어셈블리어죠.

위에 있는 그림처럼 처음 보는 사람은 절대 그 내용을 알 수 없는 내용들이 가득 차게 됩니다.

 

하지만 .NET, Java 같은 경우는 좀 다릅니다.

이것들이 만드는 코드는 하드웨어에 종속되어 있는 코드가 아닌 플랫폼에 종속된 코드를 만들게 됩니다. 바로 IL 코드입니다. 여기서 플랫폼이란 .NET Framework나 JVM이 되겠네요.

그리고 이 플랫폼들을 거쳐서 Native Code가 튀어나오게 되는 것입니다. 그리고 이 언어들은 한줄 한줄씩 컴파일되면서 실행되는 JIT(Just In Time) 컴파일을 하게 됩니다.

실행이 되는 순간에 동적으로 컴파일이 되어야 한다는 것입니다.

근데 컴파일을 하려면 결국 무엇이 필요하냐 면… 네 맞습니다. 바로 Symbol이 필요하죠. 그래서 IL 코드에는 Symbol 정보가 필요합니다.

자 이제 IL 코드에는 왜 심볼정보가 필요한지 아시겠죠??

 

간단히 말하자면… 실행이 되어야 하니까 필요합니다. 하하하하 쉽네요. ㅋㅋ

 

 

Bloger: moltak.net

'Programming > 이것저것' 카테고리의 다른 글

어셈블리어 점프 명령어  (0) 2010.04.29
Symbol  (0) 2010.04.24
초기화 하지 않은 메모리  (0) 2010.04.16
[Design Pattern] Singleton Pattern  (2) 2010.04.16
typeid 연산자  (1) 2010.04.15
힙이나 스택에서 초기화를 안하면 뭔 값이 들어갈까?? 
마소에서 마음데로 정해 줬겠지만..ㅋㅋ
그래서 검색해봤다.

0xcccccccc : 초기화 되지 않은 지역 변수
0xcdcdcdcd : 초기화되지 않은 힙에 할당된 메모리
0xdddddddd : 힙에서 free된 메모리
0xfeeefeee : 힙에서 free된 메모리
0xfdfdfdfd : 힙에 할당된 메모리의 초가 범위(할당된 메모리의 양 끝 )
이런 비밀이 있었다.


'Programming > 이것저것' 카테고리의 다른 글

Symbol  (0) 2010.04.24
IL Code에 심볼 정보가 포함되는 이유  (0) 2010.04.24
[Design Pattern] Singleton Pattern  (2) 2010.04.16
typeid 연산자  (1) 2010.04.15
enum 문자열  (0) 2010.04.09
디자인 패턴에 대해 잘 알지는 못하지만... 예전에 열심히 공부해보려 했던 때가 있습니다.
디자인 패턴을 공부하시다 보면 아시겠지만 우리가 봉착한 문제를 유연하고 멋있게 해결합니다.
그 중에 제가 가장 잘 사용하는 것이 이 Singleton Pattern 입니다.

싱글톤 패턴의 정의는 아래와 같습니다.
소프트웨어 엔지니어링 영역에서의 singleton은 객체지향 프로그래밍 시 클래스가 단 하나의 사건, 즉 단 하나의 인스턴스만을 갖도록 하는 패턴이다.  이 패턴은 주로 중요한 자원을 관리하고자 할 때, 다수의 인스턴스가 생성되지 않도록 제한하기 위해서 사용한다.  예를들어, 한번에 하나의 인스턴스만이 DB에 연결되도록 설정할때 사용할 수 있다.

여러개의 인스턴스가 생성되면 안되는 것들을 하나만 생성되게 막는 것입니다. 
일단 어떻게 사용하시는지 보시죠.

저는 어제 올렸던 KSocket을 계속 발전 시켜 나갈 것입니다.

일단 헤더파일을 보시죠.
아래와 같이 instance를 하나 선언하고 가장 중요한 것은 생성자, 파괴자를 private로 선언하는 것입니다.
아무데서나 마음대로 사용할 수 없도록.
생성자 파괴자는 이제 static 함수에 의해서만 호출 될 수 있겠죠??

그리고 아래와 같이 인스턴스를 초기화 시켜주고 인스턴스 생성자, 인스턴스 파괴자 함수를 만들어 줍니다.
간단하고 명쾌하네요. 

하지만 클래스를 만들 때마다 위 처럼 안에 함수를 생성해야 한다는 것이 너무 귀찮고 안좋아 보입니다.
그래서 아래 처럼 템플릿으로 만들었습니다.
위 블로그를 가시면 알겠지만 굉장히 간결하게 짜 놓은 것을 볼 수 있네요.
조금만 보시면 쉽게 아실 겁니다.


사용은 m_KClientSocket = KSingleton< KSocketClient >::getInstance(); 이렇게 하시면 됩니다.
하지만 위 코드는 문제점이 있죠. 생성자, 파괴자는 인스턴스 생성 함수에 의해서만 호출 한다는 것이 깨져 버렸습니다. 
이것은 다음에 해결하도록 하겠습니다.

그럼 모두들 즐프 하세요 ^^/

'Programming > 이것저것' 카테고리의 다른 글

IL Code에 심볼 정보가 포함되는 이유  (0) 2010.04.24
초기화 하지 않은 메모리  (0) 2010.04.16
typeid 연산자  (1) 2010.04.15
enum 문자열  (0) 2010.04.09
ASCII Table  (0) 2010.04.05
다른 분들도 이 연산자를 사용하는지 모르겠지만... 저는 오늘 첨 알았네용ㅠㅠ
프로그래밍을 하던 중 인스턴스에 따라서 분기를 결정해야 했습니다. 평소 하던 방법은 문자열을 넣거나 nType이라는 타입 정수를 넣어서 그것에 맞춰서 해줬죠..
하지만 오늘 검색해보니 C++에서 C#과 같은 타입 비교 연산자가 있더군요;;
놀랐습니다.ㅋㅋ
아~~~주 좋습니다. ㅋㅋ


그래서 비교 코드를 아래 처럼 바꿀 수 있었죠.

아래는 skyarro라는 아이디를 쓰시는 블로그에서 퍼왔습니다.
결과 화면입니다.



모두 즐프요~~ㅋㅋ

'Programming > 이것저것' 카테고리의 다른 글

초기화 하지 않은 메모리  (0) 2010.04.16
[Design Pattern] Singleton Pattern  (2) 2010.04.16
enum 문자열  (0) 2010.04.09
ASCII Table  (0) 2010.04.05
사용자 정의 exception (1)  (0) 2010.03.21
Socket 모듈을 짜던 중. 오류를 한글로 뿌려줄 필요가 있었다. 근데 코드 번호가 정수이므로 변수 하나를 지정해 놓고 문자열을 싹 밀어 넣은 다음에 스위치로 하나씩 빼질 필요가 있었다. 근데 이렇게 할경우 많은 메모리를 차지하게 된다. 그래서 enum을 이용한 문자열 가져오기를 생각하게 되었다. 근데 이게 C++에서는 원래 불가능 하다. 그래서 사람들이 여러가지 방향으로 돌려서 사용하는 법을 만들었는데 아직도 잘 모르겠더라... 일단은 사용만 하고 분석은 나중에 하는 방식으로;;


'Programming > 이것저것' 카테고리의 다른 글

[Design Pattern] Singleton Pattern  (2) 2010.04.16
typeid 연산자  (1) 2010.04.15
ASCII Table  (0) 2010.04.05
사용자 정의 exception (1)  (0) 2010.03.21
Handshking  (0) 2010.03.19
인터넷에서 찾기 귀찮아서 -_-;
블로그에 올려야징 -_-ㅋㅋ


'Programming > 이것저것' 카테고리의 다른 글

typeid 연산자  (1) 2010.04.15
enum 문자열  (0) 2010.04.09
사용자 정의 exception (1)  (0) 2010.03.21
Handshking  (0) 2010.03.19
Sliding Window  (0) 2010.03.19
안녕하세요. moltak 입니다. 이번에 진행할 내용은 사용자 정의 Exception 입니다. 

이번 칼럼은 (1) exception 만들기 (2) stl exception 사용하기 (3) stl exception 확장하기 순서로 진행하겠습니다.

C++을 사용할 때 예외처리를 하기 위해 try/catch를 사용하시죠? C에서는 if를 사용하겠죠.
자 일단 STL exception 을 한번 보시죠.


STL exception은 exception 클래스를 상속받아 사용됩니다. 가장 많이 사용하는 exception으로 bad_alloc이 있죠. 
exception 은 좋긴 하지만 정확한 정보를 얻기에는 조금 힘이들죠. exception을 사용하는 방법은 다음에 보도록 하고 여기서는 자신만의 exception class를 만들어 exception 이 발생했을 때 더 많은 정보를 얻도록 해보조.

일단은 자신만의 클래스를 하나 만드는 것이 좋겠죠? 저는 KException 으로 지었습니다. 그리고 아래와 같이 만들었죠.


하지만 우리는 많은 정보를 넣어야하죠. 제가 넣고 싶은 정보는 [Exception Message], [Exception Function], [Exception Line]입니다. 그것들을 받을 수 있게 다시 작성하였습니다.

위에 코드를 잠깐 설명하자면 생성자에서 [exception 종류], [exception 함수], [exception 라인]을 받아서 단순히 저장하는 역할 을 하고 있습니다. 그리고 이것들을 저장시킬 수 있는 멤버 변수들을 선언했고 m_Message에 exception 내용들을 저장해서 what() 함수에서 리턴해 주는 역할 을 하고 있습니다. 일단 예외를 발생 시켜 보죠.


위와 같이 하면 ex.what() 함수가 실행되면서 사용자 정의 메시지와, 에러가 난 함수, 그리고 라인을 볼 수있습니다.
__FUNCTION__ 과 __LINE__ 은 각각 함수와 라인을 보여 주는 매크로입니다.

근데 현재 KException는 아직 조금 부족합니다. 사용자가 what의 출력을 다르게 해주고 싶다거나 다른 변수를 넣고 싶은 경우가 있을 수 있는데 KException은 확장이 조금 어렵죠. STL Exception 을 보면 exception 클래스를 상속받아 여러가지 다른  exception 들이 존재한다는 것을 알 수 있습니다. 우리도 그렇게 만들어 보죠.

KException_File 클래스를 만들었습니다. KException_File클래스는 KException 클래스를 상속받아 구현되며 KException은 
virtual const char* what() = 0; 클래스를 만들어 추상 클래스로 만들었습니다. 이제 KException은 인스턴스화 되지 못하고 다만 자식 클래스의 인스턴스를 사용할 때만 사용됩니다. 

위와 같이 클래스 멤버 함수를 정의했습니다. 이제 어느 정도의 확장성은 가질 수 있게 되었네요. 아직 한참 더 만들어야 하지만.ㅋㅋ exception 이 발생했을 때는 아래와 같은 방법으로 받으면 되죠.

이와 같은 방법으로 자신만의 exception을 만들어서 사용 할 수있습니다. design pattern을 넣어서 조금 더 멋지게 만들면 나중에 사용하기 좋겠네요. 지금은 이쯤에서 마치도록 하겠습니다. 그럼 즐프하세요.

'Programming > 이것저것' 카테고리의 다른 글

enum 문자열  (0) 2010.04.09
ASCII Table  (0) 2010.04.05
Handshking  (0) 2010.03.19
Sliding Window  (0) 2010.03.19
CISC & RISC  (0) 2010.03.18

TCP는 두 호스트들 간에 정보를 전달하기 전에 접속이 먼저 필요하다. 그 때 3Way Handshaking 이라는 방법이 필요하게 된다.

보통 위 그림과 같은 방법이다. 그림을 보면 화살표 세개가 있는 것을 알 수 가 있다. 저게 3Way Handshaking이다. 데이터를 전송하기 전에 서로 연결 설정을 해야하는데 그 때 필요하게된다. TCP 프로토콜을 사용한다면 무조건 저 방법으로 접속을 한 후 데이터 전송이 이루어지게 된다.

두 호스트가 접속을 끊을 때는 4Way Handshaking을 사용한다.

둘이 데이터를 전송하고 있었다고 가정하자. 클라이언트가 전송이 다 되었다고 FIN/ACK를 보낸다.
① B는 A에게 종료 요청의 메시지를 담은 FIN 패킷을 전송한다.
② A는 B에게 종료메시지 FIN을 주는 것이 아닌 응답을 받았다는 의미로 ACK 패킷을 보낸다. 이것은 A가 자신은 아직 끝날 준비가 되지 않았다는 것이다.
③ A는 B에게 자신도 종료할 준비가 다 됐다는 뜻으로 FIN 패킷을 보낸다.
④ B는 알았다는 의미인 ACK를 보내는데 이 후 둘의 연결은 종료된다.

'Programming > 이것저것' 카테고리의 다른 글

ASCII Table  (0) 2010.04.05
사용자 정의 exception (1)  (0) 2010.03.21
Sliding Window  (0) 2010.03.19
CISC & RISC  (0) 2010.03.18
CISC, RISC, CRISC(EPIC)  (0) 2010.03.18
패킷이 전달될 때 버퍼가 사용이 된다는 것은 다들 알고 있을 것이다. 하지만 데이터 순서가 어떻게 되는지 어떤 방식으로 전송이 되는지에 대해서는 잘 모를 수도 있다. TCP와 같이 데이터 전송에 대해 보장하는 프로토콜 같은 경우는 슬라이딩 윈도우 라는 방식을 사용한다. 그럼 이게 무엇인지 부터 알아보자. 아래는 위키 백과에서 긁어온 내용이다.

슬라이딩 윈도

위키백과 ― 우리 모두의 백과사전.

슬라이딩 윈도(Sliding window)는 두 개의 네트워크 호스트간의 패킷의 흐름을 제어하기 위한 방법이다.

TCP와 같이 데이터의 전달을 보증하는 프로토콜에서는 패킷 하나하나가 전달되었음을 확인 신호(acknowledgement, 이하 ACK)를 받아야하며, 만약 패킷이 중도에 잘못되었거나 분실되어 확인받지 못하는 경우, 해당 패킷을 재전송해야하는 필요가 있다. 슬라이딩 윈도는 일단 '윈도(메모리 버퍼의 일정 영역)'에 포함되는 모든 패킷을 전송하고, 그 패킷들의 전달이 확인되는대로 이 윈도를 옆으로 옮김(slide)으로서 그 다음 패킷들을 전송하는 방식이다.

슬라이딩 윈도는 아직 확인을 받지 않고도 여러 패킷을 보내는 것을 가능케 하기 때문에, 매번 전송한 패킷에 대해 확인을 받아야만 그 다음 패킷을 전송하는 방법(stop-and-wait)을 사용하는 것보다 훨씬 네트워크를 효율적으로 사용할 수 있다.

http://ko.wikipedia.org/wiki/슬라이딩_윈도


쉽게 풀어 써보겠다. 우리가 100바이트의 데이터를 전송한다고 가정해 보자. send함수를 호출하면 전송될 데이터가 전송이 되는 것이 아니라 전송측 버퍼에 저장되게 된다. 그리고 수신측 연락을 기다린다. 왜냐면 수신측 버퍼가 비어있어야 데이터를 전송하면 받을 수 있기 때문이다. 수신측에서 버퍼가 30바이트 비었다고 보내라고 하면 송신측에서 30바이트를 전송한다. 또 수신측에서 50바이트를 받을 수 있다고 하면 송신측에서는 50바이트를 보낸다. 이런 식으로 데이터가 전송이 되게 된다. 


이때 송,수신측 버퍼는 모두 커널에 의해 생성된다.

'Programming > 이것저것' 카테고리의 다른 글

사용자 정의 exception (1)  (0) 2010.03.21
Handshking  (0) 2010.03.19
CISC & RISC  (0) 2010.03.18
CISC, RISC, CRISC(EPIC)  (0) 2010.03.18
펜티엄부터 린필드 i5까지, 인텔 어떻게 걸어왔나  (0) 2010.03.18

"열혈강의 윈도우즈 시스템 프로그래밍"이란 책을 보면서 의문에 빠져 들었다. 

책 내용 중 내 눈에 들어온 한 문장이 있었는데

"인텔의 32비트, 64비트 CPU 뿐만 아니라, 근래에 임베디드 환경에서 사용되는 대부분의 CPU가 RISC 구조이다."

위의 문장이었다.


난 x86은 CISC 구조이고 ARM, MIPS 등등 많은 프로세서가 RISC 구조인데 어째서 저런 말이 나왔나 생각하게 되었다.

인터넷 검색 결과 아래와 같은 문장을 발견할 수 있었다.


사실상 CISC와 RISC의 구분은 모호하다. 다만, 이전의 아키텍쳐를 계속 발전시켜온 형태의 CPU, 즉 8086부터 발전해온 x86계열을 CISC, 비교적 최근에 개발된 CPU들을 RISC라 부르게 되는 경향이 있다. 현재 둘의 경계가 모호해진 이유는 최근의 CISC CPU들이 성능향상의 방안으로 RISC의 기술들을 채용했기 때문이다. 


위와 같다면 현재 아니 예전부터 CISC는 그 구조의 한계성 때문에 성능 향상을 꾀할 수 없게 되었고 RISC의 기술을 채용했다는 것이다.

RISC는 회로가 간단해 지고 성능이 좋아진다. 단점으로는 프로세서간에 차이가 많기 때문에 명령어가 달라서 프로그램을 공유해서 사용하기 어렵다는 것이다.

CISC의 장점은 범용성이 좋은 대신에 성능은 느리고 회로가 복잡해진다.

CISC는 성능 향상을 꾀하기 위해 슈퍼스칼라 구조를 도입하는 한편 RISC 기술을 채용했다. (슈퍼스칼라가 제대로 동작하려면 RISC 구조여야 한다.)

그래서 현재는 RCISC라는 괴상한 이름을 갖게 되었다.


예전에 선보였던 프레스캇은 엄청난 열을 발생하는 CPU였다. 오죽하면 "어머니 댁에 프레스캇 한대 놔드려야 겠어요". 이말이 나왔을까.

이때가 30단계 파이프라인을 갖는다고 했다. 현재 사용되는 'i7' 린필드의 파이프라인은 14단계라고 한다. 그 때문에 클럭은 줄었지만 성능은 예전보다 훨씬 뛰어나다. (게다가 소모 전력도 더 적다.)


결론은 CISC와 RISC는 각각 장단점을 갖고 있으며 우리가 가장 많이 사용하는 IA-32(IA-32는 x86으로 불린다.)은 RCISC이다. CISC의 길다란 명령을 잘게 잘라서 RISC 처럼 처리한다.


다른 페이지가 있는데 거기도 둘러 보도록

'Programming > 이것저것' 카테고리의 다른 글

Handshking  (0) 2010.03.19
Sliding Window  (0) 2010.03.19
CISC, RISC, CRISC(EPIC)  (0) 2010.03.18
펜티엄부터 린필드 i5까지, 인텔 어떻게 걸어왔나  (0) 2010.03.18
MTU  (0) 2010.03.18

CISC(Complex Instruction Set Computer; 복합명령형 컴퓨터)
RISC(Reduced Instruction Set Computer; 축소명령형 컴퓨터)
CRISC


   MPU는 동일 칩 위에 기억회로, 논리회로를 형성한 초소형 CPU(중앙연산처리장치)인데, 그 처리구조에 따라 CISC(Complex Instruction Set Computer; 복합명령형 컴퓨터)와 RISC(Reduced Instruction Set Computer; 축소명령형 컴퓨터)로 나뉜다.


     RISC(Reduced Instructions Set Computer)가 CISC(Complex Instructions Set Computer)보다 효율적으로 명령어를 처리한다. 386이나 486 컴퓨터의 중앙처리장치가 CISC방식이고, Power PC와 워크스테이션용 중앙처리장치가 대부분 RISC방식이다. 그러나 최근에는 CISC칩도 RISC구조의 일부를 채용하여 구분이 모호해지고 있다. 따라서 addressing mode는 적어야 하고, instruction format는 다양하지 못하다.


   PowerPC(Power Optimized with Enhanced RISC PC)는 RISC(Reduced Instruction Set Computer)방식의 CPU이며 이는 Intel이나 AMD사의 CISC(Complexed Instruction Set Computer)와는 전혀 새로운 방식의 것이다. PowerPC는 IBM과 Motorola, Apple사에 의해 공동 개발된 CPU로서 PPC601, 603, 603e, 604, 604e, 740, 750(G3), 7400(G4) 순서로 발전하게 된다. RISC를 우리말로 축약형 컴퓨터라고 표현한다. 대부분의 CPU들이 방대한 명령어를 가지고 있음에도 실제로 자주 사용하는 명령어는 전체 명령어의 10%도 미치지 못함에 착안하여 명령어의 갯수를 줄이고, 그 대신 CPU 인사이드 캐시, 분기 예측 기능, 수퍼스케일러, 비순차 명령 실행, 파이프라이닝, 레지스터 개수 증가등의 본질적인 CPU 성능 개선 방안을 적용한 것이다. RISC기술은 Intel의 x86계열을 제외한 모든 CPU들, 즉 SUN의 Sparc나 DEC의 Alpha, MIPS의 R계열에 현재 채택되어 있다.


   사실상 CISC와 RISC의 구분은 모호하다. 다만, 이전의 아키텍쳐를 계속 발전시켜온 형태의 CPU, 즉 8086부터 발전해온 x86계열을 CISC, 비교적 최근에 개발된 CPU들을 RISC라 부르게 되는 경향이 있다. 현재 둘의 경계가 모호해진 이유는 최근의 CISC CPU들이 성능향상의 방안으로 RISC의 기술들을 채용했기 때문이다. 그러나 현재의 x86의 경우 오래된 아키텍쳐를 계속 발전시켜 왔기 때문에, 칩에 내장된 트랜지스터의 개수가 순수 RISC칩의 수배에 이르게 되었다. iMac에 사용되는 G3(PPC-750)의 경우 펜티엄 II의 절반에도 이르지 않는 트랜지스터의 조합으로도 더 나은 성능을 나타낸다. 최근에 개발된 G4(PPC-7400)은 펜티엄 III의 2/3의 clock만 으로도 3배이상의 성능을 보여준다. 이는 아키텍쳐가 MHz보다 더 중요하다는 것을 보여주는 단서이기도 하다.


1. CISC(Complex Instruction Set Computer)

CPU의 동작을 지시할 때 한번에 여러가지 일을 하도록 지시할 수 있는 명령어 체계를 갖는다. CPU안의 내부 명령어가 100개 이상을 사용하는 프로세서를 CISC라고 한다. 내부 명령어가 많기 때문에 기능마다 하나의 명령어를 주기 때문에 좋을 것 같이 보이지만 실제로 프로그래밍을 하기 어렵고 많은 명령어로 수행 시간이 길어질 경우가 많다. 일반적으로 사용되는 IBM 컴퓨터의 XT에서 486 CPU와 매킨토시에서 사용하는 680x0 CPU는 CISC 개념이 사용된 프로세서이다.

CISC는 인텔 ‘i80486’ ‘펜티엄’ 등의 MPU에 널리 채용되고 있는 CPU이다. CISC는 하나의 명령으로 복잡한 처리가 가능하지만 회로설계가 복잡해지는 경향이 있다.
최근 동작 주파수가 해마다 향상되어 현재는 335MHz에 달하고 있어 RISC와의 격차를 줄여 가고 있다


2. RISC(Reduced Instruction Set Computer)

CPU의 동작을 지시할 때 한번에 하나의 일만을 하도록 지시할 수 있는 명령어 체계를 갖는다. CPU안의 내부 명령어를 최소로 줄여서 수행 시간을 단축하는 것으로 단순화한 명령어를 조합해서 다른 필요한 명령어를 만드는 형태이다. 일반적으로 CISC보다 50%에서 75% 정도 더 빠르고 워크스테이션과 같은 중형 컴퓨터에 사용되는 CPU에 사용되고 있다. 모토롤라 사의 R4000은 RISC명령어 체계를 가지고 있다


최첨단 서버 워크스테이션 ‘모델 250’을 실현하는 CPU는 RISC형 CPU를 채용하고 있다. 또 인텔의 ‘펜티엄’에 대항하는 ‘파워PC’ 등도 RISC형으로 되어 있다. RISC는 종래의 CISC에서 복잡하고 종류도 많았던 명령을 정리하고 단순화하여 고속화 보드형 프로세서로 컴파일러에 의한 명령렬(列)의 최적화에 의해 고속화를 실현한다. CISC에 비해 구조가 간단하고 주파수를 높이는 일이 쉬운 것이 그 특징이다.


나아가 이 RISC를 여러 개로 병렬화하여 성능 향상을 꾀해 범용 대형 컴퓨터에 접근하고 있는 것이 최근의 서버 워크스테이션의 특징이다. <표 2>에 RISC의 상용화 예(NEC)를 나타냈다. 또 


(1) RISC, CISC,CRISC

    RISC는 정확히 말하면 `축약된 명령어 표를 이용한 정보처리방식'이다. 여기에 대비되는 것이 `복합 명령어 표를 이용한 정보처리방식' 곧 CISC이다. 386이나 486 컴퓨터의 중앙처리장치가 CISC방식이고 Power 개인용 컴퓨터와 워크스테이션용 중앙처리장치가 대부분 RISC방식이다. 펜티엄은 두 가지를 적당히 섞어 쓴다. 컴퓨터중앙처리장치는 명령어사전에서 원하는 명령어를 찾아내, 실행 시 키는 작은 반도체라고 생각하면 이 기술을 이해하기 쉽다. 물론 중앙처리장치 나름의 명령어이고, `dir'(파일목록보기) 같은 도스 명령어와는 전혀 다른 것이다. RISC방식 칩의 명령어들은 길이가 짧고 크기가 같다. 또 한 명령어는 한 가지 기능만 한다. 길이가 같아 찾기가 쉽고 기능이 한 가지밖에 없어 동시에 따로따로 처리한 뒤 결과를 합칠 수 있다. 계산기를 10개쯤 놓고 동시에 계산을 해서 합산하면 결과가 나오는 식이다. 이 때문에 명령어 처리시간이 많이 줄어든다. RISC의 장점은 CISC방식을 보면 더욱 뚜렷해진다. CISC는 명령어들의 크기가 제각각이며, 이 명령어들을 같은 크기로 잘게 잘라 처리한다 . 한 명령어를 자르니 앞뒤 순서가 생기고, 따라서 동시에 처리하지 못한다. 그렇지 않으면 뒤죽박죽이 되기 때문이다.  이런 단점 때문에 CISC방식은 인기가 떨어지고 있다. 486급 중앙처리장치의 후속제품이기 때문에 CISC방식에 바탕을 둔 펜티엄칩은 대신 잘게 자른 명령어를 동시에 처리하는 기술을 RISC방식에서 빌려왔다. 그래서 RISC와 CISC를 혼합한 CRISC방식이라고 부른다.


(2) RISC와 CISC 그 차이에 대해서

    RISC와 CISC는 CPU의 아키텍쳐,즉 구조적 측면의 차이로, 어떤 일정한 방법으로 명령어를 처리하느냐에 따라 구분된다. 예전에는 RISC를 단순히 CISC를 간소화 시킨 정도로 보는 시각도 있었지만 현재에 와서는 그런 개념을 뛰어넘고 있다. 일단 현재 우리가 대부분 쓰고 있는 CISC CPU에 대해서 설명을 해보자면 일단 CISC의 어원부터 짚고 넘어가야 할 것 같다. CISC는 Complex Instruction Set Computing의 줄인 말로, 소위 복합 명령 집합 계산,컴퓨팅으로 말 그대로 복합적인 명령어를 가지고 있다. 일단 컴퓨터에 어셈블리, 또는 베이직 따위의 언어로 명령을 주면, CPU에서 그것을 여러 단계로 세분화되어 마이크로 코드(Microcode)라 하는 수행 절차를 걸쳐 처리하게 된다. 그런데, 이런 수행에 있어 좀 더 복잡한 연산에 대응하는 명령어 셋을 추가하는 것이 CISC로, 여러 개의 단순한 명령어 셋으로 명령을 처리하기 보다는 그것들을 포괄하는 연산 셋으로 한 개의 명령어로 처리해 효율을 도모한다는 것이 CISC다. MMX도 이런 의미에서 볼 때는 CISC의 확장이라 볼 수 있겠다.


  한편, RISC는 CISC와는 반대로 기본 명령어 셋을 추구하는 형태이다. 그러나 RISC라고 해서 단순히 명령어를 간소화 시킨 형태라고 봐서는 안된다. 단순히 명령어만 간소화 시킨다면, CISC보다 뛰어날 이유가 없기 때문이다. RISC에서는 컴퓨터에서 주 수행되는 작업을 색출해, 거기에 최적화 시켜 만든다. 그러니까 핵심이 되는 작업 항목에 특화시켜 전체적인 속도를 향상시키는 것이다. 한가지 예를 들어 설명하자면, 모든 컴퓨터 작업에 있어서 읽고,쓰는 작업은 항상 포함된다. 일단 데이터를 읽어 들이고 쓰는 과정은 로딩과 스왑으로 항상 생기기 때문이다. 그 과정에 최적화시키면 그 만큼 작업 속도,즉 전체적인 처리 효과를 얻게 되는 것이다. 그러기 위해선 다른 명령어 셋과는 달리 다른 공정이 필요한데, 요즘에 와선 CISC도 이런 공정을 채용해 단일 사이클에 처리하는 명령어를 많이 갖게되었다.

요즘에 와선 이런 점을 통해서 RISC와 CISC의 차이를 구분할 수 없게 되었고, 캐시에 따른 차이가 두각을 드러냈다. 바로 CISC가 가진 맹목으로, 복합적인 명령어를 많이 가지려고 하다 보니, 트랜지스터 직접도가 과다하게 늘어나는 것이다. CISC가 가진 비효율이라 할 수 있겠다. RISC에서는 이와는 달리 명령어 체계 단순화를 지향하고, 핵심명령 특화 체제에 있어, 트랜지스터 집적에 여분이 있기 때문에 L1 캐시를 증대시켜 성능을 더욱 증대 시키는 것이다. 펜티엄 프로의 경우 L1 캐시 16KB(명령어/데이터 캐시 합친 양)이고 L2 캐시를 제외한 펜티엄 프로의 트랜지스터 집적 수가 550만개인데 반해, RISC CPU인 Power PC 604e 프로세서의 경우 L1 캐시가 64KB인데도 트랜지스터는 510만개다.

특히, 604 프로세서의 세부적인 RISC의 특성을 살펴보자면 한 실행주기당 여러 명령을 동시에 처리하는 슈퍼스칼라(6~7개의 명령어를 처리한다.)를 구현하고 있다. 이상의 서술한 점이 RISC가 CISC를 앞서는 대략적인 이유와 구조적 특징이다. R10000 프로세서 같은 워크스테이션 RISC 프로세서에 대한 언급도 하고 싶지만 그러기엔 본 필자의 역량이 너무나도 떨어지는 듯하다. 다만 O2에 사용된 R10000 프로세서를 기반해 잠깐 설명하고자 한다. R10000 프로세서의 경우 clock은 그리 높지 않다. 175MHz의 동작 clock을 가진 제품도 있기 때문이다. 1MB의 L2 캐시를 가지고 있으며,(R5000SC의 경우 5MB의 L2 캐시를 탑재하고 있다.) R10000 프로세서는 RISC프로세서의 정점을 보여주는 CPU로 RISC의 효율성을 최대한으로 발휘하고 있다. 4방향 슈퍼스칼라(4개의 명령 동시 처리)에 64비트 구조를 가지고 있으며 비순차적 명령 실행 방법과 128비트 L2 캐시 버스에 별도 5개의 실행 유닛을 가지고 있다. (PC 계열의 난폭한 마케팅을 하면 R10000 프로세서는 128비트 프로세서란 말을 들을 수도 있다는 얘기가 된다.)


   CISC는 RISC를 clock 속도로써는 충분히 능가할 수 있다. 다만 그 과정에서 트랜지스터 집적도가 너무 과다하게 올라가고 있다. 특히 Intel은 CISC에 MMX를 덧붙여 CISC에 CISC를 더한 셈이 되었다. 어차피 MMX의 세부를 열어보면 그것 역시 CISC의 확장이 되는 셈이기 때문이다. 특정 연산에 대한 명령어를 추가하는 것이 결국 CISC의 특성이 아니던가. Intel이 트랜지스터 집적도를 무리하게 올리면서 지금의 가격을 형성하고 인하 정책을 펼치는 것이 신기할 정도다. 아마도 현재의 PC CPU는 RISC로 갈 가능성은 희박할 듯 하다.

그 예로 Intel이 내세우는 차세대 CPU 머시드는 EPIC라고 하는 CISC를 또 다시 확장한 형태로 구현된다고 하니 말이다.( 그 결과 머시드의 트랜지스터 집적수는 3억개라는 천문학적인 숫자에 이르고 말았다...--;) CISC와 RISC, 이 둘은 다 각기 장단점이 있다. CISC는 복합 명령을 가짐으로써 하위 호환성을 충분히 확보할 수 있고 RISC의 경우 효율적인 CPU 구조를 가지고 있다. 다만 CISC는 트랜지스터 집적에 있어서 효율성이 결여되어 있고, 그 결과 성능 향상에 난점을 겪고, RISC의 경우 하위 호환을 위해 에뮬레이션 방식을 채택해야 하고, 일정한 환경에서만 성능을 발할 수 있는 단점이 있는 것이다. 따라서 호환성이 절대적으로 필요한 PC 환경에서는 CISC가, 전문적인 일에 있어서는 RISC가 서로 독보적인 우위에 점하고 있는 것이다.

'Programming > 이것저것' 카테고리의 다른 글

Sliding Window  (0) 2010.03.19
CISC & RISC  (0) 2010.03.18
펜티엄부터 린필드 i5까지, 인텔 어떻게 걸어왔나  (0) 2010.03.18
MTU  (0) 2010.03.18
ICMP  (0) 2010.03.18

PC의 역사가 사반세기를 넘은 지 오래지만 PC의 진화는 아직 ‘현재 진행형’이다. 처음 PC가 선보일 때만 해도 이 기계는 사무실의

업무용 컴퓨터 그 이상의 가치를 갖지 못했지만 어느새 PC는 가정의 공부방과 거실로 넘어왔다. 흑백 화면의 아스키 이미지를 조합한

조잡한 게임은 영화 수준과 비교해도 그리 흠잡기 어려울 정도의 풀 HD 수준까지 발전했고, 사무 작업 위주의 용도 역시 이제는 영화,

음악, 게임 등 엔터테인먼트 기능이 기술 발전의 큰 흐름을 만들고 있다.



CPU 역시 그러한 큰 흐름에 맞춰 끊임 없이 발전해왔다. 인텔이 ‘HD급 영상과 게임’을 내세워 코어 아키텍처 CPU를 내놓은지 3년.

그 사이에 세상은 단순 HD를 넘어 풀 HD, 그리고 그 이상의 세상을 노리고 있다. 이런 세상의 변화에 인텔은 어떤 대답을 내놓을까?

이 질문에 대해 인텔은 ‘네할렘 아키텍처’라는 새로운 기술을 해답으로서 내놓았다.


이미 2008년 말에 그 모습을 선보인 네할렘 아키텍처는 워크스테이션과 서버 시장에서 그 가치를 검증받았고, 이제 개인용 PC로

그 영역을 넓힌다. 그것이 코어 i5와 i7, 일명 ‘린필드(Lynnfiled)’ CPU다.


코어 i5의 뿌리는 펜티엄 프로

CPU의 성능을 높이는 방법 가운데 가장 쉽게 생각할 수 있는 것은 작동 속도를 높이는 것이지만, 성능이 획기적으로 좋아지지는

않는다. 더구나 속도를 무한정 끌어 올릴 수 있을 것이라는 믿음의 뿌리인 ‘무어의 법칙’만으로는 한계가 있다는 것을 지난 몇 년동안

인텔을 비롯한 반도체 기업들은 몸소 느끼게 되면서 ‘속도 만능 주의’는 더 이상 고개를 들 수 없게 되었다. 속도를 높일 수 없다면

반도체 기술의 기본 뿌리, 아키텍처(Architecture)를 바꿀 수 밖에 없다.



지난 몇 년동안 인텔은 무작정 빠른 속도에 대한 욕망을 살짝 접고 아키텍처의 개혁을 꾸준히 이어가며 새로운 CPU를 내놓았다.

‘린필드’ CPU 역시 그러한 아키텍처 개혁의 가장 최신판이다. 코어 i5와 i7의 진정한 장점을 이해하기 위해 인텔이 지금까지 어떤

생각으로 아키텍처 개혁을 이뤄왔는지 먼저 살펴봤다.


무어의 법칙 황금기, 그리고 멀티미디어 명령의 시대

린필드 코어 CPU를 비롯한 지금 팔리고 있는 대부분의 인텔 CPU들은 펜티엄 프로 시절에 처음 선보인 ‘P6’ 아키텍처에서 선보인

기술을 맨 밑의 뿌리로서 삼고 있다. 90년대 중반 등장한 펜티엄 프로는 가정용이 아닌 사무 및 전문가 전용 CPU로서 그리 많이

팔리지는 않았지만, 린필드 CPU의 증조 할머니로 불릴만한 여러 기술을 담았다.


아톰을 뺀 거의 모든 인텔 x86 CPU가 쓰는 ‘아웃오브오더(Out-of-Order)’ 명령 실행 구조를 처음 쓴 것은 펜티엄 프로이며,

32비트 환경에서 4GB 또는 그 이상의 메모리를 쓸 수 있도록 하는 변형 메모리 관리 기법인 36비트 PAE(Physical Address

Extension, 물리 메모리 확장) 역시 펜티엄 프로에서 처음 선보인 것이다. 아웃오브오더 실행 구조는 CPU가 다음 자료를 기다리며

노는 시간을 줄여 같은 작동 속도에서 성능을 크게 높여 PC 역사에 큰 획을 그었으며, CPU에 2차 캐시 메모리를 넣은 것 역시

데스크탑 PC용 x86 CPU 가운데는 펜티엄 프로가 첫 번째 테이프를 끊었다. 어찌 보면 지금 나와있는 최신 CPU의 주요 기술은

이 펜티엄 프로에 뿌리를 두고 있다 해도 좋을 것이다.



그 뒤를 잇는 펜티엄 II와 펜티엄 III는 펜티엄 프로를 바탕으로 이것을 가정용 PC에 맞게 업그레이드했다.

P6 아키텍처를 그대로 유지하면서 펜티엄 MMX CPU에 처음 선보인 ‘MMX(MultiMedia eXtension)’ 기술을 더했는데, MMX는

이미지/영상 편집과 동영상 재생, 게임 등 멀티미디어 작업에서 자주 쓰는 작업을 간단한 명령 한 번으로 실행하도록 하여 효율성을

높인 x86 CPU 최초의 SIMD(Single Instruction, Multi Data, 단일 명령 다중 데이터 처리) 기술이었다.


펜티엄 III 역시 이러한 흐름은 변함이 없는데, 공정 기술을 높여 작동 속도를 더욱 끌어 올리고, MMX의 뒤를 잇는 2세대 SIMD 명령,

SSE를 새롭게 내놓았다. 아키텍처의 큰 변화는 없지만 공정 기술을 꾸준히 끌어 올린 결과 펜티엄 III 시대에는 작동 속도가 1GHz를

넘어 최고 1.4GHz에 이르기도 했다.



펜티엄 프로부터 펜티엄 III 시절의 아키텍처 특징은 무너질 기색을 보이지 않던 무어의 법칙에 따라서 공정 기술을 차근차근 끌어

올리며 작동 속도를 높여 기본 성능을 끌어 올리고, 점차 그 비중이 커지던 영화 및 이미지 처리, 게임에 맞춰 이러한 작업의 효율성을

높이는 SIMD 기술을 받아들인 점이다. 이미 아키텍처의 큰 진화는 펜티엄 프로에서 이뤄 냈으며, 그 이후에 나온 CPU는 이 아키텍처

를 잘 다듬고 뛰어난 공정 기술의 혜택인 빠른 작동 속도를 이끌어내 사용자들의 마음을 사로 잡았다.


끊임없는 질주 펜티엄 4와 그 불편함

펜티엄 프로부터 시작된 P6 아키텍처는 세 세대를 걸쳐 그 역할을 충분히 해냈지만 인텔도 새로운 아키텍처를 고민해야만 했고,

그 결과물인 2000년에 새롭게 선보인 펜티엄 4는 P6의 마이너 업그레이드가 아닌 완전히 새로운 아키텍처, ‘넷버스트(Netbust)’

를 처음 선보인 CPU가 되었다.


넷버스트 아키텍처의 특징을 한 마디로 정리하면 ‘작동 속도를 더욱 빠르게’ 만드는 것이다.

파이프라인의 단계가 많아지면 많아질수록 같은 공정 기술을 써도 작동 속도를 높일 수 있는데, 펜티엄 4는 처음에는 20단계,

나중에는 31단계까지 파이프라인 단계를 늘렸다. 기껏해야 10개 수준인 펜티엄 III보다 훨신 많은 단계를 거쳐 명령 실행이

이뤄지게 되는데, 이렇게 파이프라인의 단계가 늘면 작동 속도는 빨라지지만, 만일 잘못 실행한 명령이나 데이터가 있으면 그

작업을 취소하고 처음부터 최고 31단계의 처리 과정을 다시 밟아야 하기에 클럭 당 실행 명령 수(IPC)가 떨어지는 문제가 생긴다.



인텔은 처리를 잘못 하는 실수를 줄여주도록 분기 예측(Branch Prediction) 효율성을 높였고, 새로운 분기 예측 기술과 더 빨라진

작동 속도를 더하면 넷버스트 아키텍처 CPU가 P6 아키텍처 모델보다 더 좋은 성능을 낼 것으로 예상했다. 여기에 CPU와 칩셋을 잇는

시스템 버스 속도를 종전의 최고 3배 수준으로 높이고 넷버스트 아키텍처에 맞춘 SSE2 기술을 더해 더욱 성능을 끌어 올렸다.


1.4GHz를 첫 모델로서 출발한 펜티엄 4는 공정 기술을 한번 더 바꾼 노스우드 코어 모델까지 큰 무리 없이 인텔의 생각대로 빠르게

속도를 끌어 올렸다. 그 사이 시스템 버스 속도는 더 빨라지고 2차 캐시 메모리 용량은 더 커졌으며 CPU 코어 하나로 두 개의

스레드(Thread)를 처리할 수 있는 가상 듀얼 CPU 기술, ‘하이퍼스레딩’이 첫 선을 보였다.

이러한 변화는 펜티엄 4의 성능을 사람들이 납득할 수 있는 수준 이상으로 높이는 데 큰 역할을 했다.


그렇지만 펜티엄 4를 내놓을 때의 생각은 몇 년만에 벽에 부딪혔는데, 더 이상 무어의 법칙이 듣지 않게 된 것이다.

무어의 법칙은 18개월마다 반도체의 속도는 두 배 빨라진다는 것인데,  130nm 공정 기술까지는 무어의 법칙을 뒷받침하기에 별

어려움이 없었지만, 90nm 공정부터는 이론에 훨씬 미치지 못하는 결과를 낳았다. 전력 소비량과 반도체 크기는 생각만큼 줄지

않았고, 이 때문에 작동 속도를 높이는 데 어려움을 겪었다.



바로 3세대 펜티엄 4 코드명 ‘프레스콧’이 그 주인공이다. 최고 4GHz에 가까운 작동 속도를 내는 데 성공했지만, 실질적으로 CPU의

성능 증가 속도는 눈에 띄게 줄어들었고, 그에 비해 발열과 전력 소모량은 엄청나게 늘었다. 때마침 불어닥친 전 세계적인 에너지

절약 열풍은 속도 만능 주의를 버리고 CPU 아키텍처를 ‘효율성’ 위주로 바꾸게 만드는 힘이 되었다.

결국 인텔은 65nm 공정 펜티엄 4 계획(일명 테자스)을 버리고 조금씩 개발을 하던 새로운 아키텍처를 빠르게 현실로 옮기는 결정을

내렸다. 바로 ‘코어 아키텍처’다.


코어 아키텍처로 연 에너지 중심의 르네상스 시대

코어 아키텍처는 펜티엄 4 시절에 나온 노트북 PC용 CPU, 펜티엄 M에서 쓰던 ‘배니어스 아키텍처’에 뿌리를 둔다.

펜티엄 M은 펜티엄 III가 쓰던 P6 아키텍처를 뿌리고 펜티엄 4의 장점인 빠른 시스템 버스와 멀티미디어 기술을 더했는데,

작동 속도는 펜티엄 4에 한참 미치지 못했지만 성능은 펜티엄 4에 그리 뒤지지 않고 전력 소비량도 적어 인기가 많았다.



2006년 코어2 듀오의 발표와 함께 첫 선을 보인 코어 아키텍처는 P6 아키텍처를 그 어머니로서 삼고 있지만 여기에 넷버스트의

장점을 더해 더 좋은 방향으로 이끌어냈다. P6 시절보다 조금 늘어난 14 단계 수준으로 줄인 파이프라인 단계는 CPU 작동 속도를

2GHz 이하로 끌어 내렸지만, 전력 소비량을 줄이고 실제 성능을 두 배 가까이 작동 속도가 빠른 빠른 펜티엄 4 수준까지 끌어 올렸다.


여기에는 명령 처리의 효율성을 높인 Micro-Ops 설계와 프레스콧 코어 펜티엄 4 CPU에서 선보인 SSE3 멀티미디어 기술, 넉넉한

2차 캐시 메모리, 그리고 펜티엄 4에서 가져온 고속 쿼드 펌프 시스템 버스의 역할이 컸다. P6 아키텍처에 없던 이러한 추가 기술은

코어 아키텍처를 ‘P6 아키텍처의 재탕’이 아닌 ‘P6와 넷버스트 아키텍처 모두의 공식 후계자’로서 인정할 만큼 좋은 성능을 보여

주었다. 1.86GHz 속도를 갖는 코어2 듀오가 2.8GHz 속도를 내는 펜티엄 4 또는 펜티엄 D보다 성능이 좋을 정도로 코어 아키텍처의

모험은 성공을 거두었다.



또한 펜티엄 D CPU에서 처음 선보였고 코어2 듀오에서 널리 쓰인 듀얼코어 기술은 코어 하나의 성능에 목을 매달던 과거의 CPU와

다른 ‘멀티 코어(Multi-Core)’로 눈을 돌리는 계기가 된다. CPU를 두 개 또는 그 이상 병렬로서 연결하는 SMP(대칭형 멀티 프로세서)

는 비록 절대 작동 속도는 빨라지지 않지만 한 번에 많은 작업/스레드를 처리할 수 있어 많은 작업을 동시에 하거나 멀티 스레드 설계를

한 작업을 하면 CPU 하나를 쓸 때보다 성능이 좋아진다.


작동 속도를 높이는 데 집착하던 P6나 넷버스트 아키텍처와 달리 과거의 아키텍처의 장점만을 살린 기본 구조와 멀티코어 기술을

바탕으로 한 코어 아키텍처 CPU는 철저히 ‘에너지 효율성’을 따졌다. 코어2 듀오 CPU는 열 설계 전력(TDP)는 65W 수준에 불과

하지만 과거의 130W를 넘나드는 수준의 펜티엄 D CPU 이상의 성능을 냈으며, 줄어든 발열은 쿨러의 소음까지 줄여 ‘조용하고

유지비 부담이 적은 CPU’라는 좋은 기억을 남겼다.

이런 인텔의 노력과 경험들을 녹인 최신 프로세서가 바로 코어 i5, i7로 이름 붙여진 린필드 프로세서다.

'Programming > 이것저것' 카테고리의 다른 글

CISC & RISC  (0) 2010.03.18
CISC, RISC, CRISC(EPIC)  (0) 2010.03.18
MTU  (0) 2010.03.18
ICMP  (0) 2010.03.18
TCP/IP PPT 에서 뜯어왔음ㅋ  (0) 2010.03.18

MTU (Maximum Transmission Unit) ; 최대 전송 단위
MTU[엠티유]는 TCP/IP 네트웍 등과 같이 패킷 또는 프레임 기반의 네트웍에서 전송될 수 있는 최대크기의 패킷 또는 프레임을 가리키며, 대개 옥텟을 단위로 사용한다.
TCP는 어떠한 전송에서라도 각 패킷의 크기를 결정하는데 있어 MTU를 사용한다.
MTU가 너무 크면 커다란 크기의 패킷을 처리할 수 없는 라우터를 만났을 때 전송 해야하는 경우가 생길 수 있다. 이와는 반대로 MTU가 너무 작으면, 대적으로 헤더 및 송수신 확인에 따르는 오버헤드가 커지게 된다.
대부분의 컴퓨터 운영체계에서는 기본적으로 대부분의 사용자에게 두루 적합한 MTU 초기치를 제공한다. 그러나, 일부 사용자들은 이 MTU 값을 변경해야할 필요가 있다.
일반적으로, 인터넷 사용자들은 MTU 기본 값을 바꿀 것인지 또는 바꾼다면 얼마로 꾸어야하는지에 대해 자신의 인터넷 서비스 공급자들의 충고를 따르는 것이 좋다.

윈도우95 사용자들의 기본 MTU 값은 1500 옥텟이며, 이것은 이더넷의 표준 MTU 값과 같다. 인터넷의 사실상의 표준 MTU는 576이지만, ISP들은 종종 1500을 사용할 것을 제시한다. 만약 웹사이트를 액세스하다가 MTU 크기가 576으로 설정되어 있는 라우터를 빈번하게 만나게된다면, 그 크기로 변경하는 것이 나을 수도 있다
(실제로는 어떻든 몇몇 사용자들은 MTU 설정을 576으로 해서 성능이 향상되었다고 주장하는 사람도 있고, 또 일부는 아무런 향상이 없다고 말하기도 한다). MTU의 최소치는 68로 설정할 수 있다.

윈도우98에서는 그들의 접속이 1500을 써야하는지 또는 576을 써야하는지를 감지할 수 있어서, 그 접속에 적합한 MTU를 선정할 수 있게 해준다. 기본 설정 값은 "자동(Automatic)"이지만, 사용자가 패킷 크기를 1500, 1000 또는 576 등과 같이 명시적으로 설정할 수도 있다. TCP 외의 프로토콜들에는 다른 MTU 크기가 적용될 수 있다.


=============== 또 다른 정의 ==============================
MTU (Maximum Transmission Unit)은 네트워크 상에 최대 전송 단위.
주어질 물리적 매체 상에서 전송 가능한 데이터의 최대 단위를 말한다. .
예) 이더넷의 MTU는 1500바이트이다

MTU란 네트워크 상에서 Maximum Transmission Unit이라는 것은 한번의 물리적인 프레임상에 전송될 수 있는 최대크기의 데이타 또는 패킷을 이야기한다. 이 패킷은 네트워크상에서 라우터가 필요로 하는 패킷의 주소와 같은 보를 싣고 있는 헤더와 트레일러(꼬리) 정보를 가지고 있다. 만약 페킷이 패킷프레임보다 더 작은 MTU를 가지고 있는 네트워크로 보내진다면 이 패킷은 불행히 쪼개져야(fragmentation,단편화) 한다. 그리고 이 조각들은 다시 조합되어야 하므로 결국은 성능저하가 생기게 되는 것이다.

MTU는 보통 MSS(Maximum Segment Size)와 RWIM(TCP Receive WINdow)와 충돌을 일으키게 되는데, MSS는 winsock이 접속 중에 받아들이려고 하는 최대 TCP데이타의 크기를 이야기한다. MSS는 MTU보다 적어도 40바이트이상 작아지는데, 이 사이즈는 헤더와 트레일러 정보 때문에 생기는 차이다. RWIN은 데이타를 받는 컴퓨터가 받기를 준비하는 데이타의 크기를 말한다. 만약 RWIN이 너무 크게 맞춰져 있다면, 하나의 패킷이 손상되거나 잃어버리게 되었을 때, 데이타의 손실이 너무 커지게 된다.

그리고 너무 작게 맞춰져 있을 때는(예를 들어, 1 x MSS), 전송이 아주 늦어지게 되는 것이다. 일반적으로 RWIN은 4x, 6x, 8x MSS 로 맞춰진다.

TCP/IP의 최대 속도는 SLIP(Serial Line Protocol)이나 PPP(Point to Point Protocol)접속을 통해 전송될 때, 무엇보다도 모뎀의 속도에 의해 결정된다. 이상적으로 생각한다면, 28.8Kbps(kilobits/s)의 속도 에서 3.2KBytes/sec의 속도를 가질 수 있어야 하고, 24Kbps접속에서는 2.7KBytes/sec의 속도를 가져할 것이다. 하지만 전송되는 TCP데이터율은 한 Byte/sec당 9bps의 모뎀 연결율(modem connect rate)를 필요로 한다.

윈도우즈의 Programs/Accessories/System 에 있는 Windows System Monitor (sysmon.exe)를 이용하면, 당신의 접속 속도를 쉽게 체크해 볼 수 있다. 데이타 전송률을 볼 수 있는 더 좋은 방법은 'Net.Medic'이라는 현재 사용하는 인터넷 브라우저와 함께 사용되는 프로그램이 있다. 이 프로그램은 인터넷을 사용하는 도중에 일어나는 문제들을 고쳐주거나, 해결방안을 마련해주도 상황들을 모니터할 수 있는 프로그램이다.

위에서 말한 데이타 전송률이라는 것은 통신상에서 획득할 수 있는 이상적인 속도를 얘기한다. 그러나 종종 네트워크 상에 보내기 전에 인터넷의 중간 IP 라우터들에서 TCP/IP요구를 조정하거나 MTU의 크기를 더 작게 다시 나누거나 하는 과정에서 이 속도는 많이 느려지는 것이다.

여러 웹 사이트들을 방문할 때, 아마도 576바이트의 IP 디폴트 MTU의 패스로 다운로드하는 라우터를 적어도 하나 이상은 만날 것이다.
그러면,이때, 당신과 또 TCP서버가 TCP 세그먼트(MSS)를 536바이트보다 크게 사용하고 있다면, 패킷을 나누기 위해 다시 느려지는
결과를 낳게 될것이다. 파일 다운로드 스피드에 상당한 영향을 미쳐 웹이나 e-mail 프로그램에서 텍스트 데이타를 받을 때나 fragmentation을 줄이는 것이 통신 환경을 개선하는 가장 중요한 부분이 될 것이다.


MTU =1500 과 576 의 차이
답> 아이넷에서는 MTU=576로 세팅하니 엄청 느려지고 인터피아에서는 꽤 빨라졌습니다.
그런데 역시나 http://www.krnic.net/net/image/connect9710.gif 을 보았더니 인터피아는 데이콤과 코넷에 E1, 미국과 T1 두개로 연결되어 있더군요. 즉, 위의 그림을 보시고 자기 ISP에서의 MTU를 최대로 쓸지 최소로 쓸지 결정하시기 바랍니다.

MTU 조절기는 http://www.iworld.net/tucows/adnload/dlmtuspeed.html 에서 다운로드 가능합니다.
먼 저, Internet의 연결된 Network Device들은 보통 MTU =1500의 Option을 사용합니다. 물론 RFC1063에 따르면 ETHERNET=1500 , POINT-TO-POINT=1500 , X.25=576 , SLIP=1006 , 등 여러 가지로 나뉘어지지만, 기본적으로 Router 및 WAN Switch로 구성된 INTERNET에서는 MTU를 1500을 사용합니다.(cisco systems 및 BayNetwork Router에서는 Default로 구성 시에 MTU=1500으로 되고, 또한 Frame-Relay 및 ATM OC-3에서도 이 Rule이 적용됩니다) 현재 WIN95 및 WINNT , HP-UX , Solaris 등 TCPIP Kernel에서는 Path-MTU -Discovery라는 Option을 사용하고 있어서 IP Header에서의 DF Bit(Don't Fragment Bit)를 1로 Marking 하여 보내고 있습니다. 이것의 의미는 자신이 보낸 IP Packet에 대해 Fragment를 허락하지 않는다는 내용입니다. ( HPUX의 경우 nettune명령으로 Option조절가능 ) 하지만 IBM MVS/TCPIP 및 Linux Old-version같은 경우는 사용을 않합니다. 만약 이러한 Frame이 Internet상의 MTU =576으로 설정되어 있는 임의의 Router로 routing 되었을 때,이 해당 Router는 Fragment를 하려하나 DF Bit이 1로 되어 있어 실패하고 해당 IP Source에게 "ICMP Type=3 Code=4 Fragment Need , but DF Bit=1"의 Message를 보내게 됩니다(Header에 Next-Hop MTU를 포함하여).이것을 Client에서 받았을 때에는 PMTU의 크기를 해당 Next-Hop MTU에 맞추어 줄여서 보내게 되고, 또한 RoutingPath 변경으로 인한 PMTU 증가는 Timer로 주기적(2분 또는 10분)으로 PMTU Size를 증가하여 ICMP Message를 받을 때 까지 MTU Size를 증가 시킨 후 DF=1로 Marking하게 됩니다. 이러한 Internet상에서의 Routing Path변경이 흔하지 않으므로 이 같은 MTU Size증가는 드물게 일어납니다 (만약 Firewall에서 이러한 ICMP Type을 Deny했다면 MTU Size가 틀리고 DF=1로 인해 Router가 Client에게 알려주려는 ICMP Message가 유실되어 Client측에서는 아무런 조치도 못하고 멍청하게 Hold되어 버립니다

외국 News Group에 이런 내용으로 하소연하는 Network Administrator을 많이 보았습니다,이런 경우에는 Sniffer또는 Network Monitor로 Packet을 Dump하여 초기 TCP Handshake때에 MSS(아래부분에 설명)를 확인하여 틀릴 경우에 1.MTU를 작은 쪽으로 맞추어 주거나 2.Firewall에서 ICMP Deny를 삭제하여준다)
-ICMP Type=3 Code=4 Message
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type =3 | Code =4 | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unused =0 | Next-Hop MTU |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Datagram Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* 이전에는 Next-Hop MTU가 없었으나 RFC1191에서 Propose된 후에 추가 되었슴. 또한 TCP Header의 초기 3-Way Handshake시에 Option Field의 MSS가 있는데 이것도 MTU 와 관계가 깊습니다. MSS란 Maximum Segment Size로 TCP Stack이 Sliding Window Buffer에서한번에 전송할 수 있는 Data Size수가 됩니다.보통 MTU -20Byte(IP Header) -20Byte(TCP Header)로 계산 되어 설정됩니다.
보통 MTU 를 1500사용 하므로 MSS=1460 증 한번의 TCP Packet전송으로 보낼 수 있는 Data Size는 1460 Byte가 되는 거죠.
초 창기 Internet에서는 TCP가 단순하게 IP Destination이 Non-Local일 경우에 536(576- 20-20)으로 설정하고 Local인 경우에는 1460(1500-20-20)로 설정하였다-아직도 IBM MVS/TCPIP는 이 Rule을 사용하고 있다 (IBM/MVS Tcpip Parameter에 Default로 놓을 경우 이렇게 되고 MTU를 1500으로 바꾸려면 해당 Network에 직접 1500을 기술하여야 한다, 이렇게 바꾸더라도 역시 PMTU 는 사용하지 못한다- DF Bit=0.역시 IBM은 Internetwrking 보다는 SNA로만 장사해야 될 것 같다 ) 물론 MSS Size는 초기 MSS Negotiation시에 작은 수로 맞추어 집니다.

octet ; 옥텟
컴퓨터에서의 옥텟은 8 비트의 배열을 말한다. 그러므로, 옥텟 한 개는 일반적으로 8 비트로 구성된 한 바이트와 같다.
그러나, 모든 컴퓨터 시스템이 8 비트를 1 바이트로 사용하지는 않기 때문에, 8 비트 한 셋을 일컫는 분명한 의미 제공을 위해 옥텟이라는 용어가 사용된다.

이 용어를 8진수의 의미를 갖는 octal과 혼동해서는 안된다.


octal ; 8진법

Octal은 8진법을 가리키는 용어이다. 8진법에서는 숫자들이 0, 1, 2, 3, 4, 5, 6, 및 7 등 8가지의 문자를 이용하여 구성된다.
7 다음의 숫자는 10이며, 17 다음의 숫자는 20 등으로 변해나간다. 컴퓨터 프로그래밍에서, 8진수는 2진수에 비해 짧게 표기할 수 있다는 장점 때문에 2진수 대신 사용되는 경우가 있다.

'Programming > 이것저것' 카테고리의 다른 글

CISC, RISC, CRISC(EPIC)  (0) 2010.03.18
펜티엄부터 린필드 i5까지, 인텔 어떻게 걸어왔나  (0) 2010.03.18
ICMP  (0) 2010.03.18
TCP/IP PPT 에서 뜯어왔음ㅋ  (0) 2010.03.18
OSI 7Layer  (0) 2010.03.18
1. ICMP란?

ICMP(Internet Control Message Protocol)는 기술적으로 오류보고 메커니즘(Error Reporting Mechanism)입니다. ICMP는 오류를 감지한 라우터가 최초 근원지에 오류를 보고할 수 있는 방법을 제공합니다. 호스트 서버와 게이트웨이 사이에서 메시지를 제어하고 에러를 알려주는 프로토콜로서 RFC 792에 명시되어 있습니다.

데이터그램이 오류를 유발하면, ICMP는 데이터그램의 최초 근원지에만 오류 상태임을 보고할 수 있습니다. 중계 라우터의 문제를 알려줄 수 없기때문에, 사실상 어떤 라우터가 문제를 일으켰는지 판단할 수 있는 확률이 낮습니다.

그럼 왜 ICMP는 최초 근원지에게만 오류를 보고할까요? 데이터그램에는 출발지와 최종 목적지 주소만 지정할 수 있기 때문입니다. 따라서 지나가는 경로에 대해서는 알 수 있는 길이 없습니다.

Snap3.bmp
2. ICMP 메시지 전달

ICMP 메시지는 두 단계의 캡슐화 과정을 거칩니다.
ICMP 데이터영역 + ICMP 헤더

데이터그램 데이터영역          + 데이터그램 헤더

프레임 데이터영역                                  + 프레임 헤더
ICMP 메시지는 IP를 이용합니다. 즉, OSI Layer 3계층에 해당하는 프로토콜입니다.
IP 데이터그램에 캡슐화도고 IP를 통하여 전송이 됩니다.

ICMP 메시지는 오류 메시지를 전송하지만, 메시지 자체의 오류에 대한 ICMP 메시지는 생성되지 않습니다.


3. 메시지 포맷

ICMP는 세가지의 필드로 이루어져 있습니다.

"TYPE"필드 - 8비트이며, 메시지를 식별하는 일을 합니다.
"CODE"필드 - 8비트이며, 메시지 타입에 대한 추가적인 정보를 제공합니다.
"CHECKSUM"필드 - 16비트이며, 체크섬을 제공합니다.

오류를 보고하기 위한 ICMP 메시지는 헤더에 추가적으로 문제를 발생시킨 데이터그램의 옥텟을 포함합니다.
오류 발생시 어떤 애플리케이션이 문제를 일으킨 것인지 정확하게 알기 하기 위해서, 문제를 유발시킨 데이터그램의 부분을 직접적으로 되돌려 주는 것입니다.

* 참고 : ICMP TYPE 별 메시지 종류

 TYPE 필드

 ICMP 메시지 종류

 0

에코 응답(echo reply) 

 3

목적지 도달 불가능(destination unreachable) 

 4

 근원지 억제

(source quench)

 5

경로 변경(redirect) 

 6

 대체 호스트 주소

(alternate host address)

 8

 에코 요청(echo request)

 9

 RA(router advertisement)

 10

 RS(router soliciation)

 11

 데이터그램에 대한 시간 초과

(time exceeded for a datagram)

 12

 데이터그램의 파라미터 문제

(parameter problem on a datagram)

 13

 타임스탬프 요청(timestamp request)

 14

 타임스탬프 응답(timestamp reply)

 15

 정보 요청(information request)

 16

 정보 응답(information reply)

 17

 주소 마스크 요청

(address mast request)

 18

 주소 마스크 응답

(address mask reply)

 30

 Traceroute



4. PING

ping은 사용자가 ICMP echo request를 보낼 수 있도록 하는 명령어입니다. 이것은 네트워크 문제를 식별하기 위하여 사용을 하는데, 호스트가 ICMP echo request 메시지를 목적지로 전송합니다. 그리고나면 echo request 메시지를 받은 대상은 echo reply 메시지를 전송받은 쪽으로 되돌려 주어야 합니다. 이렇게 echo request와 echo reply 메시지를 주고 받음으로 인해서 호스트는 목적지에 도달 가능한 지, 응답을 하는지 검사하기 위해 사용됩니다.

따라서 이 성공적인 응답을 통해서 시스템의 주요 부분들이 제대로 동작하는지 확인할 수 있습니다.

이렇게 정상적인 응답이 가능하기 위한 다음과 같은 조건들이 있습니다.
1. 호스트 컴퓨터의 IP 소프트웨어는 데이터그램을 포워딩할 수 있어야 합니다.
2. 호스트와 목적지 간의 중계 라우터가 동작 중이고, 데이터그램을 정확히 전달해야 합니다.
3. 목적지 컴퓨터는 동작중이어야 하고 ICMP와 IP 소프트웨어가 동작해야 합니다.
4. 응답이 되돌아오는 경로에 놓인 모든 라우터들의 라우팅 테이블 정보가 전달 가능한 경로를 구성해야 합니다.


* 참고 : ICMP destination unreachable 메시지

 Code 값

의 미 

 0

네트워크 도달 불가능 

 1

 호스트 도달 불가능

 2

 프로토콜 도달 불가능

 3

 포트 도달 불가능

 4

 단편화가 필요하지만 DF 비트가 설정됨

 5

 소스 라우팅 실패

 6

 목적지 네트워크를 알 수 없음

 7

 목적지 호스트를 알 수 없음

 8

 근원지 호스트가 격리됨

 9

 관리상의 이유로 목적지 네트워크와의 통신이 금지됨

 10

 관리상의 이유로 목적지 호스트와의 통신이 금지됨

 11

 TOS에 대한 네트워크 도달 불가능

 12

 TOS에 대한 호스트 도달 불가능

 13

 관리상의 이유로 통신 필터에 의해 금지됨

 14

 호스트 우선순위 위반

 15

 사실상 우선순위 미달


'Programming > 이것저것' 카테고리의 다른 글

펜티엄부터 린필드 i5까지, 인텔 어떻게 걸어왔나  (0) 2010.03.18
MTU  (0) 2010.03.18
TCP/IP PPT 에서 뜯어왔음ㅋ  (0) 2010.03.18
OSI 7Layer  (0) 2010.03.18
광역 변수  (0) 2010.03.18

Snap1.pngSnap2.pngSnap3.pngSnap4.pngSnap5.pngSnap6.pngSnap7.png

'Programming > 이것저것' 카테고리의 다른 글

MTU  (0) 2010.03.18
ICMP  (0) 2010.03.18
OSI 7Layer  (0) 2010.03.18
광역 변수  (0) 2010.03.18
Virtual Function  (0) 2010.03.18

프로토콜은 한마디로 통신규약입니다.

예를 들자면:

SERIAL , 페러렐 (예전 프린터에서 많이 사용하던 방식), IEEE방식,USB,ETHERNET등

다양하지요.

그리고 프로토콜군이라 함은

각각의 통신에도 세분화가 많이 되어 있는데 (SERIAL도 RS-232,RS-422,RS-485등,

USB 1.0, 1.1, 2.0등) 이걸 세분화 하지 않고 집단으로 총칭하는 것을 프로토콜군이라고 표현하는 듯 하네요.


장비나 컴퓨터를 만드는 회사들은 세계에 수도 없이 많은데 서로 통신함에 있어서 규칙을 만들어서 범용화를 시키고 발전시키면서 오늘날에 도달한것입니다.

컴퓨터 발전에도 이 프로토콜이 없었다면 훨씬 뒤쳐진 발전을 했으리라 생각됩니다.


다 타이핑하자면 기니까 아래 기술 문서를 퍼왔으니 참조하시기 바랍니다.



그리고  OSI7계층에 대한 설명도 아래에 있으니 참조바랍니다.


프로토콜의 정의:


정보기기 사이 즉 컴퓨터끼리 또는 컴퓨터와 단말기 사이 등에서 정보교환이 필요한 경우, 이를 원활하게 하기 위하여 정한 여러 가지 통신규칙과 방법에 대한 약속 즉, 통신의 규약을 의미한다.

통신규약이라 함은 상호간의 접속이나 절단방식, 통신방식, 주고받을 자료의 형식, 오류검출방식, 코드변환방식,전송속도 등에 대하여 정하는 것을 말한다. 일반적으로 기종()이 다른 컴퓨터는 통신규약도 다르기 때문에, 기종이 다른 컴퓨터간에 정보통신을 하려면 표준 프로토콜을 설정하여 각각 이를 채택하여 통신망을 구축해야 한다. 대표적인 표준 프로토콜의 예를 든다면 인터넷에서 사용하고 있는 TCP/IP가 이에 해당된다.

정보통신의 상대방은 일반적으로 원격지에 있다. 따라서 정보를 전송하기 위해서는 정보를 전기적인 신호의 형태로 변환하고 그 변환된 신호가 통신망을 통해 흐르도록 하는데, 통신망에는 정상적인 신호의 흐름을 훼방하는 여러 가지 현상이 존재하게 된다. 이러한 현상은 정확한 정보의 전송을 방해하여 도중에 오류가 발생되는 원인이 된다.

프로토콜이라는 규약의 집합 속에는 이러한 오류에 대응하기 위한 약속이 대단히 중요하다. 또한 정보를 정확하고 효율적으로 전송하기 위해서는 송수신 개체 간에 서로 정보의 전송 시점과 수신 시점을 맞추는 일(동기화)도 수행해야 하고, 정보 흐름의 양을 조절하는 흐름 제어방법도 역시 사전에 약속하여 프로토콜 속에 포함해야 한다.

이러한 오류제어, 동기, 흐름제어, 코드변환, 전송속도 등에 대한 약속 이외에도 통신하는 상대방의 위치에 따라 통신 개체가 어느 OSI 계층에 있는 가와 효율적인 정보전송을 위한 기법, 정보의 안전성(보안)에 관한 약속들도 프로토콜의 범주에 포함되어야 한다.


OSI


네트워크는 수많은 컴퓨터와 장비로 이뤄져 있다. 신기한 것은 이들 구성요소들이 모두 말이 통한다는 것. 장비의 개발업체도 다르고 사용하는 운영체제도 다르지만, 네트워크를 통해 서로 통신을 할 수 있는 것은 바로 프로토콜 때문이다. 때문에 프로토콜은 네트워크가 성립되기 위한 가장 기본적이 요소 중 하나다.
이제 일반명사라고 해도 과언이 아닐 정도로 많이 사용되는 프로토콜은 원래 외교협약같은 좀더 고상한 용어다. 즉 말이 통하지 않는 두 장비가 의사소통을 하기 위한 절차나 규칙 등을 체계적으로 정리해 놓은 것이다.


OSI 참조모델에 대한 오해
초기의 네트워크 역시 프로토콜에 따라 통신을 했다. 하지만 OSI 7계층 참조모델(Open System Interconnection Reference Model)이 등장하기 전까지의 네트워크 프로토콜은 IBM의 SNA나 DEC의 DECNet처럼 특정 업체가 자사의 장비들을 연결하기 위해 만든 것들이었다. 따라서 서로 다른 네트워크 간에는 호환되지 않는다는 한계를 갖고 있었다.
OSI 7계층 참조모델은 이런 문제를 해결하기 위해 ISO가 제정한 것이다. OSI 참조모델은 네트워크 통신의 전 과정을 7계층으로 나누고, 각 계층마다 일정한 역할을 수행하도록 해 하나의 네트워크 통신이 완성되는 과정을 나타낸 것이다. 말 그대로 “이런 식으로 프로토콜을 만들면 서로 호환될 수 있으니, 프로토콜들은 이것을 참조하라”는 것이다. 
OSI 참조모델에 대한 가장 큰 오해는 바로 모든 네트워크 프로토콜이 OSI 참조모델에 따라 7계층 구조를 갖고 있을 것이라고 생각하는 것이다. 
네트워크는 목적에 따라 두세 단계의 프로토콜만으로도 원하는 통신을 할 수 있다. 따라서 억지로 7단계로 통신 절차를 나눌 필요는 없다. 실제로 우리가 사용하는 네트워크 프로토콜과 OSI 참조모델이 직접적으로 대응되는 경우는 그리 많지 않으며, 많은 프로토콜이 OSI 참조모델의 여러 계층에 걸친 기능을 제공한다. “이 프로토콜은 3~4계층에서 동작한다”는 말을 많이 듣게 되는 것도 이 때문이다. 
이런 특징 때문에 OSI 참조모델은 초보자가 네트워크를 이해하는 데 더없이 훌륭한 교재가 되고 있다. OSI 참조 모델은 실제 네트워크 프로토콜을 이해하기 쉽도록 만들어, 네트워크 프로토콜의 역할과 구조, 나아가 네트워크의 동작 방식을 쉽게 이해할 수 있도록 해준다.


계층화된 프로토콜의 역할
(표 1)은 OSI 참조 모델을 정리한 것이다. 여기서 가장 아래 부분인 물리 계층부터 각각의 계층마다 고유의 작업들이 정의돼 있다. 
또한 각 계층은 반드시 자신의 영역에서 운영되는 하위 계층을 통해 서비스를 받고, 상위 계층으로 서비스를 제공하도록 규정돼 있다. 예를 들면 3계층의 네트워크 계층은 2계층인 데이터링크 계층을 통해 서비스를 받고, 상위 계층인 전송 계층에 작업한 내용을 서비스하는 식이다.
한편 각 계층은 전송 데이터에 각 계층에서의 요구 조건과 처리 정보를 포함한 헤더라는 고유의 제어 정보를 전달 메시지에 추가해 다음 계층으로 보내며, 수신측의 동일 계층에 의해 해석돼 처리된다. 예를 들면 송신측 컴퓨터의 5계층에서 추가된 헤더는 수신측 컴퓨터의 5계층에서 해석되며, 해석된 헤더는 지정된 작업을 수행한 다음 제거된 상태로 다음 계층으로 넘어가, 최종적으로 수신측 컴퓨터에는 데이터만 전송된다.
이때 각 계층 간에 전달되는 데이터의 단위는 계층에 따라 서로 다른 이름으로 불리며, 이를 ‘서비스 데이터 단위’라고 한다.
프로토콜이 데이터를 전송하기 위해 사용하는 기본 단위를 PDU(Protocol Data Unit)라고 한다. 즉, 물건을 운반할 때 상자 단위로 포장해 운반하는 것과 같이 프로토콜은 정보의 운반을 위해 PDU라는 상자를 이용하는 것이다. 
상자 단위로 물건을 포장해서 운반할 때 상자마다 물품의 내용이나 발송처, 수신처 등을 표기하는 것과 마찬가지로 PDU에도 사용자 정보뿐만 아니라 데이터의 발신처와 수신처에 대한 주소 정보와 전송 중에 에러가 발생했는지 확인하기 위한 패리티, 그밖에 흐름 제어 등을 위한 각종 정보가 함께 들어간다.
계층화된 프로토콜에서는 계층마다 PDU 이름을 독특하게 붙여 사용하는 경우가 있다(표 2). 2계층 PDU는 프레임(Frame), 3계층 PDU는 패킷(Packet), 4계층 PDU는 세그먼트(Segment) 등으로 부르는 것이 일반적이다. 그리고 특별한 이름이 없는 경우에는 그냥 몇 계층의 PDU라고 부른다. 특히 세그먼트라고 불리는 4계층 PDU는 TCP에서 사용하는 경우가 많다.



TCP/IP와 OSI 참조 모델
일반적으로 가장 많이 사용되는 TCP/IP를 통해 OSI 참조 모델과 프로토콜에 대해 알아보자.
TCP/IP는 좁은 의미로는 1969년 미국방부가 제시한 ARPNET (Advanced Research Projects Agency NETwork)에서 제안한 프로토콜의 집합 중 인터네트워킹에 대한 핵심적 기능을 제공하는 TCP와 IP만을 지칭한다. 하지만 OSI의 3계층에서 7계층까지 해당 소프트웨어나 서비스 관련 프로토콜을 통틀어 얘기할 때도 사용한다.
TCP/IP는 3계층 프로토콜인 IP와 4계층 프로토콜인 TCP가 합쳐진 용어다(그림 2). 네트워크 계층에 해당하는 IP는 네트워크 환경에 흩어져있는 여러 노드 중에서 지정된 목적지를 찾아가는 경로를 설정하는 작업을 수행하고, TCP는 안정된 데이터 전송을 위해 흐름과 오류를 제어하는 역할을 맡는다.
TCP 외에 또 다른 4계층 프로토콜 중 하나인 UDP(User Datagram Protocol)는 TCP와는 달리 데이터의 신뢰성있는 전송을 보장하지는 않는다. 그러나 신뢰성이 매우 높은 회선을 사용하거나 데이터의 확실한 전송을 요하지 않는 통신, 또는 한번에 많은 상대에게 메시지를 전송할 경우에는 보다 효율적이다.
일반적인 고속 이더넷 환경에서 FTP를 통해 서버에 접속하는 경우를 OSI 참조 모델을 통해 생각해 보자. 우선 클라이언트의 FTP 클라이언트는 애플리케이션 계층의 프로토콜인 FTP 규격에 맞춰 데이터에 헤더를 붙여 하위 계층으로 전송하고, 4계층 TCP 프로토콜이 수신측 서버의 4계층과 통신을 통해 데이터의 정합성을 테스트하고 오류가 있을 경우 재전송을 하는 등의 일을 처리한다. 또한 3계층에서는 IP 어드레스를 통해 송신측이 특정 수신측을 지정하고 경로를 설정한다.
그 아래의 2계층과 1계층에서는 두 노드 사이의 물리적인 연결과 디지털 데이터를 전기적인 신호로 변환해 전송하고 신호가 약할 경우에는 증폭하는 등의 일을 처리한다.



OSI 참조모델의 계층별 이해


물리 계층
OSI 7계층 참조 모델의 1계층은 물리 계층이다. 이 계층에서 담당하는 것은 네트워크 케이블과 신호에 대한 것으로, 물리적 신호(bit)의 전송 규칙을 조정하는 역할을 한다.
물리 계층은 전송 매체에 대한 규정은 정하지 않지만, 이를 구현하는 방법적인 면에서는 전송 매체와 깊은 관계를 맺고 있다. 참고로 물리 계층과 관련된 네트워크 연결 장비들은 다음과 같다.


- 허브나 리피터 등의 전기적 신호를 재발생시키는 장비
- 각종 커넥터와 같은 전송 매체 연결 소자 등의 기계적인 연결 장치
- MODEM, CODEC 등 디지털/아날로그 신호 변환기


기본적으로 네트워크는 일대일 또는 멀티 포인트 방식으로 연결된다. 잘 알고 있듯이 일대일 방식은 두 통신 장비들이 직접 연결된 상태를 말한다. 이런 식으로 연결하면 회선을 전용으로 사용할 수 있으므로, 장비간 정해진 전송 용량과 대역폭을 보장받을 수 있다. 한편 멀티 포인트 연결은 3대 이상의 장비를 연결하는 방식을 말한다. 이 방식은 같은 주파수대를 공유하며, 전송 매체에 연결된 모든 장비가 전체 기능을 공유할 수 있다. 일반적으로 대규모 네트워크를 구축할 경우에는 일대일 연결과 다중점 방식을 적절히 혼합하는 방식으로 설계한다.
이 같이 다양하게 연결된 네트워크의 형태를 토폴로지라고 부른다. 즉, 어떤 형태나 구조로 연결된 것을 네트워크 토폴로지(Network Topology)라고 이해하면 된다. 단, 눈으로 보이는 물리적인 토폴로지 형태가 논리적으로는 동일하지 않을 수도 있다. 일반적인 토폴로지에는 버스형(Bus), 링형(Ring), 스타형(Star), 메시형(Mesh), 셀룰러형(Cellular) 등이 있다.
1계층에서는 이외에도 전기적인 펄스나 광학적인 방법 또는 전자기적 파동을 통해 신호를 전달하는 방법에 대한 정의도 수행하며, 동기화 방식, 대역폭 등에 대한 개념을 정의한다.


데이터 링크 계층
OSI 참조 모델의 두 번째 계층인 데이터링크 계층은 데이터 패킷을 생성하고 전송하는 방법을 규정하는 프로토콜에 대한 계층이다. 이 계층이 하는 일은 물리 계층에서 넘어오는 데이터의 오류를 검사하고 복구 기능을 담당할 뿐 아니라, 시스템 간 전송 속도 차에 의한 오류나 흐름 제어까지 도맡아 처리한다. 쉽게 얘기하자면 화물을 트럭에 싣고, 각 트럭을 고속도로로 보내며 화물이 무사히 목적지에 도착하도록 관리하는 역할을 담당한다.
다른 모든 계층과 마찬가지로 데이터링크 계층 또한 고유의 식별 정보를 전송 데이터 앞에 붙이고 있다. 이 정보에는 수신자와 송신자(물리적 또는 하드웨어적인)의 어드레스와 프레임 길이, 그리고 상위 계층의 정보가 포함돼 있다. 이 계층에 속하는 네트워크 연결 장비로는 브리지, 지능형 허브 등을 들 수 있다.
데이터 링크 계층의 여러 기능은 대개 MAC(Media Access Control)과 LLC(Logical Link Control)의 두 가지 계층으로 다시 세분화할 수 있다. MAC 계층은 동일 채널을 공유하는 통신 방법을 제어하기 위한 것이고, LLC 계층은 데이터 전송을 위해 각 장비들을 논리적으로 연결하고, 연결을 유지하는 역할을 담당한다.


네트워크 계층
네트워크 계층은 여러 개의 독립적인 네트워크 사이에서 데이터 전송에 관한 계층이다. 앞서 설명한 데이터링크 계층의 데이터 전송은 물리적인 장치의 어드레스 지정을 통해 단일 네트워크로 연결된 모든 장치에 데이터를 브로드캐스팅하며, 수신측 장비에서 확인해 자신에게 오는 데이터를 수신받는 방식이다. 
그러나 네트워크 계층에서는 네트워크와 네트워크를 연결하는 인터네트워킹 환경에서 특정 경로를 선택해 권한이 없는 네트워크에 데이터를 전송하는 것을 미연에 방지할 수 있다. 또한 서로 다른 네트워크로 구성된 인터네트워킹을 통해 올바른 데이터 경로를 보장할 수도 있다. 네트워크 계층에서는 기본적으로 다음과 같은 사항을 수행한다.


- 논리적으로 분리된 모든 네트워크에 고유한 네트워크 어드레스를 부여한다.
- 인터네트워크를 통해 컴퓨터와 라우터가 최적의 데이터 경로를 결정하도록 라우팅을 구현한다.
- 네트워크는 인터네트워크 내에서 예상되는 오류의 개수에 따라 서로 다른 단계의 연결 서비스를 구현한다.


전송 계층
전송 계층은 복잡한 하위 계층 구조를 상위 계층이 알 필요가 없도록 감추기 위한 계층이다. 여기서는 상위 계층의 메시지를 세그먼트화한 후, 이 세그먼트를 세션 계층이나 상위 계층 프로세스에게 신뢰성 있게 전달하는 역할을 한다. 전송 계층은 하위 계층에서의 신뢰성이 모자라는 연결 서비스나 연결 지향 연결 서비스가 갖는 미비점을 해소하기 위한 역할을 수행한다. 여기서 신뢰성이 보장된다는 말은 데이터가 항상 전달된다는 것을 의미하지는 않는다. 
예를 들어 케이블이 끊어졌을 경우에는 데이터의 전달을 보장할 수 없다. 만일 어떤 데이터가 수신측 장치에게 올바르게 전달되지 않은 경우, 전송 계층은 재전송을 개시하거나 상위 계층에게 이 사실을 통보할 수 있으며, 이에 근거해 상위 계층에서는 필요한 조치를 취하거나 사용자에게 옵션을 제공하게 된다.


세션 계층
세션 계층은 상위 계층에서 필요로 하는 서버 이름과 어드레스를 하위 계층에서 제공되는 논리 어드레스 정보를 사용해 식별할 뿐 아니라, 서비스 제공자와 요청자 간을 연결하고 대화를 개시하는 역할을 담당한다. 이 기능을 수행하는 경우 세션 계층은 각 네트워크 구성 요소를 소개하거나 식별해내며 액세스 권한을 조정하기도 한다.


프리젠테이션 계층
프리젠테이션 계층은 변환과 암호화를 통해 데이터를 주고받는 서로 다른 환경의 컴퓨터와 애플리케이션이 데이터를 이해할 수 있도록 돕는 기능을 수행한다.


애플리케이션 계층
사용자로부터 데이터를 받아 하위 계층으로 전달하고, 하위 계층에서 전달하는 데이터를 사용자에게 전달하는 애플리케이션 계층은 여러 가지 실제적인 네트워크 서비스를 제공하는 계층이다.
애플리케이션 계층에는 각각의 네트워크 서비스에 대한 특정한 주제와 기능이 포함된다. 다시 말해, 이 계층 하부에 있는 여섯 계층이 일반적으로 네트워크 서비스를 지원하는 기술과 작업을 포함하는데 반해, 애플리케이션 계층에서는 특정 네트워크 서비스 기능을 수행하는데 필요한 프로토콜을 지원한다.
애플리케이션 계층 프로토콜이 지원하는 서비스로는 네트워크 서비스에 해당하는 파일, 프린트, 메시지, 애플리케이션, 데이터베이스 서비스 등이 포함된다. 
OSI 7계층을 만든 이유는 프로토콜을 체계적으로 연구하기 위한 목적 외에도, 공용으로 사용할 수 있는 공개된 프로토콜을 만들기 위한 것도 있었다. 그러나 7계층이 발표된 시점에 이미 많은 프로토콜이 사용되고 있었고, 특히 WAN에서는 TCP/IP가 표준으로 자리잡아 독보적인 위치를 확보하고 있었다. 
그 이후, 1계층과 2계층에서는 이더넷, 3계층과 4계층에서는 TCP/IP, NetBEUI, IPX 등이 업계 표준으로 자리잡았다.
한편 5, 6, 7계층은 각각이 별도로 구현되기보다는 통합된 형태의 서비스라는 이름으로 제공된다. 텔넷, FTP, 전자우편(SMTP, POP), HTTP, 뉴스그룹(NNTP), NetBIOS 등이 이와 같은 서비스에 해당한다.

'Programming > 이것저것' 카테고리의 다른 글

ICMP  (0) 2010.03.18
TCP/IP PPT 에서 뜯어왔음ㅋ  (0) 2010.03.18
광역 변수  (0) 2010.03.18
Virtual Function  (0) 2010.03.18
Virtual Destructor  (0) 2010.03.18

광역 변수를 사용할 때는 꼭 초기화를 해 주어야 한다. 초기화 해주는 부분은 main.cpp 에서 하는 것과 같이 해 주면 된다.

 // head.h

extern int a;

extern int b;


// main.cpp

#include "head.h"


int a = 10;

int b = 20;


void main()

{

a = 1;

b = 2;

}


// sub.cpp

#include "head.h"


void sub()

{

a = 2;

b = 3;

}

'Programming > 이것저것' 카테고리의 다른 글

TCP/IP PPT 에서 뜯어왔음ㅋ  (0) 2010.03.18
OSI 7Layer  (0) 2010.03.18
Virtual Function  (0) 2010.03.18
Virtual Destructor  (0) 2010.03.18
try/catch와 if/else의 차이점  (0) 2010.03.18

상속에서 중요한 것 중 하나는 부모가 자식을 가리킬 수 있다는 것이다.

다음 소스를 보자.

Snap4.png

내 기대는 p->fucntion(); 문장이 "Derived"를  호출하는 것이었지만 결과는 "Base"를 호출한다.

왜 그럴까?


위 이유는 포인터의 형이 정해진 시점에서 이미 호출되어질 함수가 정해지기 때문이다.

포인터 p함수는 Base로 형이 선언되어 있기 때문에 자신의 함수 밖에 호출할 수 가 없다.

즉, 포인터가 무엇을 가리키든지 간에 Base로 형이 선언되어 있어서 호출 할 수 있는 함수도 정해져 있다는 것이다.


위의 결과를 제대로 보이게 해주는 것이 virtual 키워드 이다.

함수의 리턴타입 앞에 virtual이라는 키워드를 붙여주면 가상함수가 된다.


부모 클래스에만 virtual을 붙여주면 되지만, 보통은 자식 클래스에도 붙여서 명시한다.

virtual 키워드를 붙여주면 우리가 원하는데로 값이 출력되는 것을 볼 수 있다.

가상함수는 정적 결합(많이 들어본 용어일 것이다. 정확히는 링킹시에 결합이다.)을 하지 않고 동적 결합(실행 중에 결정된다.)을 사용한다.


Snap5.png


문장을 위와 같이 고치면 원하는 결과가 출력되는 것을 볼 수 있다.


'Programming > 이것저것' 카테고리의 다른 글

OSI 7Layer  (0) 2010.03.18
광역 변수  (0) 2010.03.18
Virtual Destructor  (0) 2010.03.18
try/catch와 if/else의 차이점  (0) 2010.03.18
C++ Style Type Casting  (0) 2010.03.18

왜 가상 파괴자가 필요한지 예를 통해서 보도록 하자.

아래는 우리가 일반적으로 사용하는 상속의 사용 예이다.

Snap1.png


우리는 Derived 클래스가 Base를 상속받게 하고 Base 클래스를 포인터로 선언해

Derived를 생성해주고 있다.

우리는 생성과 파괴가 아래처럼 되기를 원할 것이다.

Snap2.png


하지만 결과는 아래와 같이 나온다.

Snap3.png

왜 그럴까..??


위 이유는 포인터의 형이 정해진 시점에서 이미 호출되어질 함수가 정해지기 때문이다.

포인터 p함수는 Base로 형이 선언되어 있기 때문에 자신의 함수 밖에 호출할 수 가 없다.

즉, 포인터가 무엇을 가리키든지 간에 Base로 형이 선언되어 있어서 호출 할 수 있는 함수도 정해져 있다는 것이다.


생성자의 경우는 소스에서 보듯이 new Derived를 했기 때문에 우리가 명시적으로 호출을 해주고 있지만.

파괴자의 경우는 Base의 파괴자만 호출이 되는 것이 맞다. 왜냐면 p함수는 Base 형이기 때문에.


그렇기 때문에 아래와 같은 소스로 바꿔야 한다.

Snap4.png

위 소스와 같이 Base의 파괴자를 가상함수로 선언하게 되면 p의 파괴자가 동적바인딩이 되게 된다.

virtual 함수는 정적인 함수 호출을 동적 호출로 바꿀 수 있게 해주는 것이다.

위으 Base는 가상함수가 되며 동적 바인딩이 가능해진다. 동적바인딩이 되어 Base 형의 파괴자가

실행되는 것이 아니라 Derived의 파괴자가 실행되며 그 후 Base의 파괴자가 실행되어 완전한 메모리

해제가 이루어 진다.


'Programming > 이것저것' 카테고리의 다른 글

광역 변수  (0) 2010.03.18
Virtual Function  (0) 2010.03.18
try/catch와 if/else의 차이점  (0) 2010.03.18
C++ Style Type Casting  (0) 2010.03.18
#pragma pack  (0) 2010.03.18

try와 if는 장단점이 존재하고 있었습니다. 일단 둘의 차이점은 try 구문에서 예외가 발생하면 그 즉시 블록이 종료가 되고 catch 블록으로 제어가 이동된다고 합니다. 그리고 try/catch는 블럭if/else 는 구문이라는 점이 다릅니다.


if/else 로 에러를 처리한다면 에러가 발생한 객체에 대해서 수명이 유지되기 때문에 에러를 처리하는 동안에도 에러가 발생한 객체를 참조하는 코드가 정상적으로 컴파일 된다. 어떤 예외가 발생했을 경우 try/catch 안의 모든 객체는 스코프를 벗어나 참조 할 수 없게 되지만 if/else 문은 스코프가 벗어 나지 않게 되므로 try/catch 보다 더 위험합니다. 또한 활성 스택에서 생성되는 지역객체들의 자동 소멸을 위해 그것의 정보들을 유지합니다. 따라서 if문의 예외처리와는 달리 지역 객체들의 소멸자가 자동으로 호출되므로 메모리 등 리소스 누수의 문제를 조금이나마 해결할 수 있습니다.


하지만 try/catch 의 단점도 존재하게 됩니다. try/catch 블록은 유지해야 할 정보도 많고 또 실제 예외가 발생 했을 때도 해주어야 할 일이 많기 때문에 당연히 코드 크기나 예외 발생시 처리 속도는if/else의 전통적인 반환 값을 통한 오류처리와는 비교하기 힘듭니다.

 

하지만 try/catch는 자동으로 해주는 일이 많으며 당연히 더 느립니다. 하지만 우리가 만들어낸 코드가 컴파일러가 자동으로 만들어준 코드보다 더 안전하다고 말하기는 힘들겠네요.

Snap1.png


예외를 던질 때 단순히 기본형을 넘기는 것이 아니라, 예외 처리를 위해 미리 만들어진 클래스의 임시 객체를 넘기면 보다 자세한 정보를 catch 핸들러가 얻을 수 있습니다.


하지만 try/catch 를 사용하는 것은 검사코드가 포함되고 stack unwinding을 위한 코드가 추가되기 때문에 실행 파일의 크기를 약간 증가시키고 실행 속도를 약간 감소시킵니다.
예외 처리의 이러한 단점 때문에, 예외 처리는 사용되어야 할 곳에만 사용하는 것이 바람직합니다. (어떤 프로그래머는 DirectX로 개발하는 게임 프로그램의 렌더링 루프에서는 try/catch를 사용하지 않는다고 한다.)

'Programming > 이것저것' 카테고리의 다른 글

Virtual Function  (0) 2010.03.18
Virtual Destructor  (0) 2010.03.18
C++ Style Type Casting  (0) 2010.03.18
#pragma pack  (0) 2010.03.18
#define swap  (0) 2010.03.18

C++에서는 static_cast, const_cast, dynamic_cast, reinterpret_cast의 4가지 casting이 지원된다. 사용 형식은 다음과 같다.

xxxxx_cast<type>(value)

  • const_cast : 상수 객체나 상수 포인터의 상수성을 제거하려는 목적을 갖는다.
  • dynamic_cast : 상위 클래스의 포인터에서 하위 클래스의 포인터로 변환하는 것을 뜻한다. 이 때, 변환에 성공한 경우(즉, 원래의 포인터가 조상 클래스의 포인터인 경우)에는 유효한 포인터가 제대로 리턴되고, 실패한 경우(두 포인터 타입 간에 연관이 없는 경우)에는 NULL이 리턴된다. dynamic_cast보다는 virtual 함수를 사용하는 것이 원래는 더 깔끔한 방법이지만, 라이브러리 안에 들어있는 클래스들이라서 직접 소스 수정이 불가능하다거나한 경우에는 이것을 사용한다(static_cast보다는 안전하다). - Effective C++ 항목 39 참조.
  • reinterpret_cast : 함수 포인터 타입을 형변환하는 것과 같이 구현에 따라 달라지는 결과를 위한 형변환을 목적으로 사용된다. 또한, 포인터 형변환 시에 static_cast로는 불가능한 경우에 사용할 수 있다(예 : void*를 Student*로 바꾼다거나..)
  • static_cast : 일종의 잡동사니 형변환이다. 어떤 형변환도 적합치 않을 때 사용할 수 있다. 의미상으로 볼 때는 기존 C의 형변환에 해당한다.

기존의 형변환도 그대로 사용되지만 새로운 형태의 형변환을 사용하는 것이 좋다. 코드에서 찾아보기도 쉽고 (사람뿐만 아니라 grep 같은 툴에게도 쉽다.) 보다 전문화된 목적의 형변환 형태가 컴파일러가 사용 에러를 진단하는 것을 가능하게도 해주기 때문이다.

'Programming > 이것저것' 카테고리의 다른 글

Virtual Function  (0) 2010.03.18
Virtual Destructor  (0) 2010.03.18
try/catch와 if/else의 차이점  (0) 2010.03.18
#pragma pack  (0) 2010.03.18
#define swap  (0) 2010.03.18

+ Recent posts