BLOG main image
전체 (276)
[Computer] (42)
[Programming] (62)
[DBMS] (26)
[Operating System] (21)
[Study English] (8)
[For money] (28)
[Interest] (89)
«   2009/11   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30          
77889 Visitors up to today!
Today 81 hit, Yesterday 46 hit
'C언어'에 해당되는 글 4건
[폭주기관차, 2007/12/20 22:52, [Programming]/Visual C++ API/MFC]
예외처리는 Java에서 처음 개념을 봤다.

VB에서의 ON ERROR GOTO ~ 처럼 에러가 나면 자동으로
그 분기로 점프하는건줄 알았는데 그거랑은 약간
달른 것이었다.

하지만 조금만 생각해보니 ON ERROR GOTO도 구현할 수 있을꺼
같았고 오히려 ON ERROR GOTO보다 더 유용할 뜻 보인다.
(이전까지는 예외 처리가(try ~ catch가) 왜 있는지 몰랐다.)

우선 내가 그동안은 try ~ catch를 등한시 여기다가 갑자기 관심을 갖게 된 것은
필요한 곳을 찾았기 때문이다.

그동안 코딩을 하면서 메모리 누수가 발생해도 어쩌다가 발생한거니
그리 크게 생각 안하고 대충 프로그램 다시 실행하여서 오류 안나는 동작만
하곤 했다.
하지만 try ~ catch를 다시 곰곰히 보니 어떻게 써야 할지 알았다.

char *pMem = (char *)malloc( 40 * sizeof( char ) );

if( pMem == NULL )
    return FALSE;
   
while( 1 )
{
  이런 저런 수행 문;
   
  if( 에러 발생? )
  {
    if( pMem != NULL )
    {
      free( pMem );
      pMem = NULL;
      return FALSE;
    }
  }
}

if( pMem != NULL )
{
  free( pMem );
  pMem = NULL;
  return TRUE;
}

여기서 처럼 난 항상 if문으로 에러 났을 경우 상황을 대처하곤 했다.
그래도 별 문제는 없었다.

하지만 오늘 발생하고야 말았다. 그것은 if문으로 에러 처리를 할 경우
코드가 너무 방대해지고, 같은 코드를 계속 넣어야 한다는 것이다.

    if( pMem != NULL )
    {
      free( pMem );
      pMem = NULL;
      return FALSE;
    }


프로그램 수행중 에러가 나고 함수에서 빠져 나갈때 잡았던 메모리를 풀어줘야 한다.
그런데 이 구문을 수행하지 않고 리턴을 하게 된다면, 처음에야 오류가 나지 않지만
나중에 가서 알 수 없게 오류가 발생하게 된다.

물론 코딩할때 신중하게 저 코드를 다 써준다면 괜찮지만, 문제는 귀차니즘과 유지보수에
있다.
저런 코드를 매번 삽입하는 번거로움은 둘째 치고, 만약 메모리 변수를 하나 더 선언하게
된다면?

char *pTmp = (char *)malloc( 10 * sizeof( char ) );


이 변수를 추가 한다면 return FALSE, return TRUE; 구문 전에 free(pTmp) 라는 구문을
더 추가 해줘야한다. 한 줄 뿐이겠지만, 나중에 코드가 복잡해진다면 일일이 찾아
넣기란 매우 번거롭고 헷갈릴 것이다.

이를 try ~ catch문으로 쉽게 해결 할 수 있게 되었다.


< try ~ catch문의 간단한 이론 부분 보기 > - 클릭



중요한것은 try, catch, throw, finally 43가지가 있다.

우선 위의 예제부터 try ~ catch로 바꾸어 보자

char *pMem = (char *)malloc( 40 * sizeof( char ) );
BOOL  bResult = TRUE;

try
{
  if( pMem == NULL )
      throw "메모리할당 에러";
     
  while( 1 )
  {
    이런 저런 수행 문;
     
    if( 에러 발생? )
    {
      throw "기타 에러 발생";
    }
  }
}
catch( char *pE )
{
  printf( "에러 발생\r\n   %s", pE );
 
  bResult = FALSE;
}
 
finally
{

  if( pMem != NULL )
  {
    free( pMem );
    pMem = NULL;
  }
 
}

return bResult;

이렇게 변할 것이다.
길이 상으론 오히려 더 복잡해 보인다.
하지만 프로젝트가 커질 수록 오히려 이런 방식이 유지보수하고, 오류 처리에 더 간단할 것이다.

그리고 try ~ catch에 관한 또 다른 예제문도 밑에 있다.
그냥 지나치기엔 안깝고도 자세한 설명이기에 그대로 긁어옴
(출처는 맨 밑에 표기 해뒀습니다)

<좀더 자세한 예제 보기>



출처 : kv20님의 글
(수정일 : 2007년 12월 27일)
Trackback Address :: http://kongmks.cafe24.com/trackback/271
Name
Password
Homepage
Secret
[폭주기관차, 2007/12/05 13:22, [Programming]/Visual C++ API/MFC]
한가지 이름의 함수에 여러가지 동작을 수행하게 할 수 있다.

아래와 같은 클래스가 있다고 보자

class class_A {
public:
    int (*test)(int a)
};


A라는 클래스안에 test란 포인터형 함수가 있다.

지금까지 선언하던 함수랑은 살짝 다르다...

다음과 같은 경우를 보자.

int *test(int a);


이 함수의 세부 사항을 보면

함수이름 : test
매개변수 : int a
반환형식 : int *


이런 뜻이 된다. 그렇다면 아까와 같이 괄호를 치면 어떤 의미가 될 것인가.

int (*test)(int a);

함수이름 : *test
매개변수 : int a
반환형식 : int

그렇다 함수앞에 *(포인트)가 붙은 것이다.

그렇다면 이런 것을 어떻게 사용할까?

아래의 예제를 보자.


int print_a( int a );
{
    printf("a = %d\r\n", a);
   
    return 0;
}

int print_b( int b );
{
    printf("b = %d\r\n", b);
   
    return 0;
}

int (*test)(int a);

int main(void)
{
    test = &print_a;                // 포인터형 test함수에 print_a함수의 주소를 넣었다.
   
    test(1);                          // 포인터형 test함수를 호출했다.
                                        // test 함수는 print_a의 함수 주소를 가지고 있으므로
                                        // print_a함수를 수행한다.

    test = &print_b;

    test(2);

    return 0;
}


출력결과는
a = 1
b = 2


어디에서 응용이 가능한가...?

클래스를 만들때 어떤 동작은 다른 개발자에게 넘겨주고 싶을 때가 있다.
이런 경우는 파생클래스를 만들어서 오버라이딩을 할 수도 있지만
함수 하나만 다른 개발자가 원하는 코드로 사용하게 하고 싶을 경우가 있다.


설명하기 힘드므로 아래와 같은 예를 보자

void 휴식( int)


이런 함수가 있다.

휴식은 클래스를 만들때 정하지 않고 다른 프로그래머가 내 클래스 코드를 사용할때
따로 지정하여 사용하게 하고 싶다면 아래와 같이 선언을 한다.

class 일상{
public:
    void (*휴식)(int);
};


이렇게 클래스를 선언해두면 다른 개발자가 '일상'이라는 클래스를 사용할때 굳이 파생클래스를 이용하지
않더라도 사용할 수가 있다.

void 내휴식(int)
{
    자동차구매();
}

void main(void)
{
    일상 = 폭주기관차;
   
    폭주기관차.휴식 = &내휴식;
   
    폭주기관차.휴식(200);   
}

Trackback Address :: http://kongmks.cafe24.com/trackback/269
Name
Password
Homepage
Secret
[폭주기관차, 2007/02/22 13:00, [Programming]/Visual C++ API/MFC]
    int a = 1;

    printf("%d %d %d %d\n", ++a, ++a, ++a, ++a);


어떤 결과 값이 예상 되는가?
아래 결과는 Visual C++ 6.0에서 수행한 결과이다.

결과 값:
  5 4 3 2


이 것은 변수가 좌측에서 부터 수행되는 것이 아니라 우측에서 부터
좌측으로 수행이 된다는 것이다.

a = 1 + 2 + 3 + 4
라는 공식이 있으면 뒤에서부터 3+4 한 후 결과 값 2 + 7, 결과 값 1 + 9에서
결과 값 10을 도출해낸 다는 것이다.

이것을 모르면 나중에 버그나도 원인을 찾기 꽤 까다롭게 된다.
좌측 부터 수행되는 줄 알고 아래와 같이 수행 했다면...
int a = 3;

gotoxy( ++a, a );


사실 개발자는 gotoxy( 4, 4 )가 호출되길 원했었지만 위의 코드는 매개변수에
gotoxy( 4, 3 )이 들어가게 된다.

뭐 사실 이 방식은 컴파일러에 따라 좌측부터 수행되는 것이 있고 하기 때문에
아래와 같이 쓰는 것이 훨씬 더 좋은 코드라 할 수 있다.
int a = 3;

++a;

gotoxy( a, a );


무조건 코드를 어렵게 한다고 좋은 것이 아니다.
혼동이 될 것 같은 것은 저런식으로 표기를 해야 나중에 유지보수도 편하고, 컴파일러를
옮겼을 때 원하는 결과 값을 얻기 쉽다.

우측에서 좌측으로 수행하는 순서는 언어에 따라 다르지 않고 컴파일러에 따라 다릅니다.
Turbo C++과 볼란드 C++에서의 결과 값이 다를 수도 있습니다.

Trackback Address :: http://kongmks.cafe24.com/trackback/136
Name
Password
Homepage
Secret
[폭주기관차, 2007/02/22 12:56, [Programming]/Visual C++ API/MFC]
if( 1조건 && 2조건 )


만약 1조건이 참이고, 2조건도 참일경우 IF문 안의 문장을 수행하게 된다.
만약 1조건이 거짓일 경우는 2조건이 참이듯, 거짓이든 결과는 거짓이 되게 된다.
그래서 2조건은 아예 수행도 안한다.

글로는 이해가 안 갈 것이다. 아래의 예를 보자

    int a = 30, b = 40;

    if( a == 20 && ++b == 41 );

    printf("a=%d, b=%d", a,b);


결과 값:
   a = 30, b = 40


1조건 : a == 20
2조건 : ++b == 41

1조건이 거짓이었다.
2조건은 ++b이므로 b가 41이 되어야 하는데, 결과는 40이었다.
즉, 1조건이 거짓이므로 자동으로 2조건은 수행하지 않았다.

아래 예제도 보자.

    int a = 30, b = 40;

    if( a == 20 || ++b == 41 );

    printf("a=%d, b=%d", a,b);


결과 값:
   a = 30, b = 41


b가 41이 되었다는 것은 2조건을 수행 했다는 뜻이다.
OR연산(||)의 경우 1조건이 거짓이더라도 2조건이 참이면 IF문 안의
코드를 수행해야하므로 2조건을 수행했지만
AND연산(&&)의 경우 1조건이 거짓이면 2조건이 참이듯 거짓이든
결국 IF문 코드를 수행하지 않으므로 자동으로 2조건을 수행하지
않는 것이다.

본 실습 결과값은 Visual C++ 6.0에서 수행되었습니다.

Trackback Address :: http://kongmks.cafe24.com/trackback/135
Name
Password
Homepage
Secret
*1