블로그 이미지
하루, 글. 그림. 영상매체. 표현을 도와주는 기기들. 도전 중. 동화다아아
    동화다아아

    카테고리

    분류 전체보기 (176)
    잡담 (1)
    IT 기기-리뷰&뉴스 (7)
    리뷰 - 도서 (1)
    리뷰 - 영상 (0)
    리뷰 - 그림/음악 (1)
    내장형 하드웨어 (163)
    Total
    Today
    Yesterday
    - 예제(main.c,  g++ 컴파일)
    #include<stdio.h>

    void
     test(int A, int B)
    {
      printf("%d\n", A);
      printf("%d\n", B);

      return ;
    }

    int main()
    {
      test(12);
      test(3);
      test();
      
      return 0;
    }

     → 출력 결과는


     → 위의 예제는 gcc로는 컴파일 되지 않고 g++로 컴파일 가능하다.
     → 함수 인자에서 "int B=3"과 같은 경우, 즉 인자에 값을 미리 주는 경우는 오른쪽 부터 주었을 때만 가능하다.
     → void test(int A=1, int B) 와 같이 선언하면 컴파일 에러가 발생한다.
     → 즉, void test(int A=1, int B=3) or void test(int A, int B=3)의 경우에만 컴파일이 가능하다.
     → 호출할 때의 값이 최우선이며, 다음으로 인자의 값을 우선한다.
     → cl로 컴파일 했을 때도 같은 결과를 호출한다.(확장자를 cpp로 변경하여 컴파일)




    - 오버 로딩 (-> iostream.h를 가진 main1.c 파일을 작성하여 테스트)
     → 같은 이름을 가진 세개의 함수(void test()를 생성한다. 여기서 인자는 각각, (int, int), (int, float), (int)의 세가지로 한다.
     → main에서 각각의 함수를 호출하여 중간파일을 생성해본다.(g++ --save-temps main1 main1.c)
     → 소스 작성
    #include<iostream.h>
    // 오버 로딩 test
    void test(int A, int B)
    {
      cout << A << endl;
      cout << B << endl;
    }
    void test(int A, float B)
    {
      cout << A << endl;
      cout << B << endl;
    }
    void test(int A)
    {
      cout << A << endl;
    }

    int main()
    {
      test(13);
      test(13.1f);
      test(1);

      return 0;
    }

     → 출력 결과
    1
    3
    1
    3.1
    1

     → 함수의 이름이 같으면 생길 수 있는 문제를 고려해서 컴파일러는 함수의 이름을 바꾼다.(명칭 부호화), 중간파일(.s)를 살펴보면 아래와 같은 것을 볼 수 있다.

     → 살펴보면 test() 함수는 3번 호출에 각각 test__Fii, test__Fif, test__Fi의 3가지로 이름이 바뀌어 있는 것을 확인할 수 있다.(명칭 부호화) 함수 이름뒤에 __(언더바)가 붙어 있고 그 뒤에 F, 그리고 인자에 따라 int형은 i, float 형은 f로 이름지어져 있는 것을 확인할 수 있다.

     → cl로 중간파일 생성하여 확인(cl main.cpp /FA)
     → main.asm 확인
    PUBLIC  _main
    _TEXT  SEGMENT
    _main  PROC NEAR
    ; Line 19
      push  ebp
      mov  ebp, esp
    ; Line 20
      push  3
      push  1
      call  ?test@@YAXHH@Z        ; test
      add  esp, 8
    ; Line 21
      push  1078355558        ; 40466666H
      push  1
      call  ?test@@YAXHM@Z        ; test
      add  esp, 8
    ; Line 22
      push  1
      call  ?test@@YAXH@Z        ; test
      add  esp, 4
    ; Line 24
      xor  eax, eax
    ; Line 25
      pop  ebp
      ret  0
    _main  ENDP
    _TEXT  ENDS

     → cl 컴파일러의 경우에는  
    ?test@@YAXHH@Z 
    ?test@@YAXHM@Z 
    ?test@@YAXH@Z
     의 3가지로 이름이 바뀐 것을 확인할 수 있다.
     → 여기서 문제는 cl 컴파일러로 컴파일 해서 확인한 결과와 g++ 컴파일러로 컴파일 한 결과 test 이름이 바뀐 형식이 다르다는 것을 알 수 있다. 즉, 명칭 부호의 적용 방식이 다른데 이로 인해 라이브러리를 만들어 사용한다고 했을 때 컴파일러가 다른 것에 따른 문제가 발생할 수 있다.
     → 이를 위해 컴파일러가 함수 이름 변경을 하지 못하게 막는 기법을 알아보면
     → 소스의 함수 앞에 extern "C" 를 붙여본다.
    extern "C" void test(int A)
    {
      cout << A << endl;
    }

     → 위와 같고 중간파일을 생성하여 확인하면

     → 위처럼 해당 하는 함수의 이름이 test로 되어 있는 것을 확인할 수 있다. 

     
       call  ?test@@YAXHH@Z        ; test
      add  esp, 8
    ; Line 22
      push  1078355558        ; 40466666H
      push  1
      call  ?test@@YAXHM@Z        ; test
      add  esp, 8
    ; Line 23
      push  1
      call  _test
      add  esp, 
    4

     → 즉, extern "C" 를 사용하여 컴파일러가 함수의 이름을 바꾸는 것을 막을 수도 있는데, 중복해서 같은 이름의 함수에 사용할 수 는 없다. 왜냐면 컴파일러가 기계어로 변환하는 과정에서 구별할 수 없기 때문이다.
     → 따라서 g++의 경우 컴파일 에러가 발생한다.
     → Cl의 경우 중복 컴파일도 가능한데 단, 이때는 함수의 이름이 둘다 명칭부호 형식에 따라 바뀐다.
    ※ 오버로딩 규칙 재확인 
    → test(char A)
    → test(int A)
    → test('A');으로 호출할 경우 역시 에러가 발생한다.(애매하다. 즉, 이렇게 사용하면 안된다.)
    ※ 참고로 포인터에 NULL을 넣지 말고 0 을 넣자. NULL은 C에서 (void *)0으로 디파인 되어 있고 이것은 C++에서 형변환 문제를 발생시킬 수 있다. C는 형변환이 너그럽지만 C++이나 자바는 엄격하여 에러를 발생시킬 수 있다.

    - 전역변수의 동적 초기화
     → 전역변수는 컴파일 시점에 값을 초기화 한다.(code, data, bss는 컴파일 과정에 메모리에 생성)
     → 지역변수는 실행될때 생성된다.(heap, stack)
     → 지역변수에 static을 사용하면 정적 변수가 되어 컴파일 단계에 초기화가 된다.
    →  static int A = 10이라고 main() 내에 선언되면 이 변수는 컴파일시 10이 들어간다.)
     → 만약 C에서 전역 변수를 동적으로 사용하려 하면 에러가 발생할 것이다.
    #include<stdio.h>

    int
     test(void)
    {  
      int iNum;
      printf("숫자를 입력하세요.\n");
      scanf("%d"&iNum);
      return iNum;
    }

    int A = test();

    int main()
    {
      printf("%d\n", A);  

      return 0;
    }

     → 위의 예제를 gcc로 컴파일 하면 에러이다.
    main2.c: 12:  initializer element is not constant
     → 단, g++으로는 컴파일이 되는데,  C++에서는 전역변수의 동적 초기화가 가능한 것을 알 수 있다.
     → 실행해 보면

     → C++도 C와 같이 main()이 엔트리 포인트는 맞지만 반드시 제일 처음 실행되는 함수가 아니다.(C는 반드시 제일 처음 호출)
     → 전역 변수를 최초 할당하는데 변수가 일반 함수를 필요로 할 경우 main() 보다 먼저 호출한다.(C에서는 불가능)
     → 즉, main() 실행전에 에러가 나서 문제가 발생할 수도 있다.
    ※ .cxx도 C++의 확장자

    - 클래스(구조체를 확장한 것)
     자료의 추상화
     → 프로그램을 보호하면서 함수를 이용해서 프로그래밍 한다.
     → 함수 첫번째 줄만 사용자에게 제공하며, 정해진 함수만 사용하도록 유도한다.
    #include<iostream.h>
    #include<stdlib.h>


    struct emb
    {
      int *item;
      int iNum;  
    };
    // 구조체 초기화 함수
    bool embInit(emb *stVal)
    {
      // 분홍색 값은 리터럴(문자상수)이다.
      if(0 == stVal) // Null 을 입력받으면
      {
        return false;
      }
      stVal->item = 0;
      stVal->iNum = 0;

      return true;
    }
    bool embInit(emb *stVal, unsigned int uiNum)
    {
      // 분홍색 값은 리터럴(문자상수)이다.
      if(0 == stVal) // Null 을 입력받으면
      {
        return false;
      }
      else if(0 == uiNum)
      {
        return false;
      }
      // item에 동적 할당
      stVal->item = (int *)malloc(sizeof(int)*uiNum);
      // 동적 할당을 못 받았을 경우
      if(0 == stVal->item)
      {
        return false;
      }
      stVal->iNum = uiNum;

      return true;
    }
    void embFree(emb *stVal)
    {
      if(0 == stVal)
      {
        return ;
      }
      if(0 == stVal->item)
      {
        return ;
      }
      free(stVal->item);
      stVal->item = 0;
      stVal->iNum = 0;
    }

    int main()
    {
      emb OBJ;
      // 자료의 추상화
      // OBJ에 함수만이 접근하고 main()은 접근하지 않는다.
      // 즉, 함수를 통해서 간접적으로 건드리게 하는데
      // 이것을 OBJ가 추상화 되었다. 자료가 추상화 되었다고 한다.
      embInit(&OBJ); // 0으로 초기화 하는 함수
      embInit(&OBJ, 300); // 동적할당 및 전체 계수(1200byte)
      embFree(&OBJ);
      
      return 0;
    }

     → 함수를 통해서 OBJ에 접근하게 한다.
     → 자료형을 감싸서 함부로 접근하지 못하게 한다.



     
    Posted by 동화다아아
    , |

    최근에 달린 댓글

    최근에 받은 트랙백

    글 보관함