ref:http://blog.daum.net/coolprogramming/60



const는 컴파일러 상수로 변수의 값을 상수화하여 한번 값으로 할당된 메모리의 모든 비트를 변경 불가하게 만듭니다.

사용방법은 간단합니다.

const int g = 500;
void main( )
{
    const int n = 10;
    printf("%d %d\n", g, n);
}
  1. 500 10

 자료형 선언 앞에 const키워드만 붙이면 됩니다. g와 n은 이제 변수(메모리변경가능)가 아니라 상수(메모리변경불가)로 취급됩니다.

만약 변경하려 하면 컴파일러 오류입니다.

const int g = 500;
void main( )
{
    const int n = 10;
    printf("%d %d\n", g, n);

    g = 100; // 변경불가 컴파일러 에러~
    n = 20; // 변경불가 컴파일러 에러~
}

 에러~~

 아래는 g와 n변수의 메모리 그림입니다.

 

 

상수 만드는 거야 const만 붙이면 되므로 아주 쉽죠?!

 

 여기서 궁금합니다. const상수와 enum상수와 define 상수의 차이점이? 지금은 간단히 정리하고 넘어갑니다. 다음에..

  • const상수 : 변수 메모리영역에 생성되며 변수이지만 컴파일러에 의해 변경이 불가능해 집니다.
  • enum상수 : 상수이며 실행시 메모리이름 없는 실제 값 자체입니다.
  • define상수 : 상수이며 전처리기에 의해 컴파일전에 값으로 치환됩니다.

지금은 어렵죠? 지금은 걍! 모두 상수다 알아 두세요!

 

const는 배열이나 포인터변수와 결합되어 엄청난 장점을 발휘합니다.

포인터 변수와 결합되어 사용될 때, 세 가지 정도로 나뉠 수 있습니다.

int n = 10; 변수가 있고 int* pn = &n; 과 같이 n의 주소를 pn이 가리킬 때

 

  1. const  int  *  pn = &n;       ( int const * pn = &n ; 와 같은 코드 )

    • *pn은 변경불가, pn은 변경가능
  2.          int   * const pn = &n;

    • *pn은 변경가능, pn은 변경불가
  3. const int * const pn = &n;

    • *pn은 변경불가, pn도 변경불가

이해하면 쉽습니다. const가 *pn 앞에 붙었나? ( const * pn ) 아니면 const가 pn 앞에 붙었나? ( * const pn)을 잘 보시면 됩니다.

void main( )
{
    int n = 10;
    const int * pn1 = &n;
    int * const pn2 = &n;
    const int * const pn3 = &n;

    *pn1 = 20; // 변경불가 컴파일러 에러~
    pn1 = &n; // 변경가능 0

    *pn2 = 20; // 변경가능 0
    pn2 = &n; // 변경불가 컴파일러 에러~

    *pn3 = 20; // 변경불가 컴파일러 에러~
    pn3 = &n; // 변경불가 컴파일러 에러~

    printf("%d %d %d\n", *pn1, *pn2, *pn3);
}

 위 코드를 꼭 이해하시고 기억하세요. 예제 코드에서 자주 사용하게 됩니다.

위 예제를 그림으로 설명하면 아래와 같습니다.

 

 

 

마지막으로 const 사용 예제를 보고 const 마무리하도록 하겠습니다. 나머지는 프로그램 실습에서 경험하세요.

void PrintStringconst char * str)
{
    puts(str);
}
void PrintArrayconst int * arr)
{
    int i;
    for( i = 0 ; i < 5 ; i++)
        printf("%3d", arr[i]);
    puts("");
}
void main( )
{
    char *str = "Hello!";
    int arr[5] = { 10, 20, 30, 40, 50};

    PrintString( str );
    PrintArray( arr );
}
  1. Hello!
     10 20 30 40 50

함수와 포인터 부분을 공부했다면 예제는 어렵지 않게 이해할 수 있습니다.

함수의 매개변수 앞에 const가 있는 것을 잘 보세요. 위 예제는 const가 있든 없든 잘 돌아 갑니다. 그렇다면, 왜? const를 붙였을까요? 각 함수 내에서 문자열이나 배열의 요소를 변경하지 않기 위한 보장입니다. 위 예제는 만약 실수로 각 함수 내에서 str이나 arr을 사용하여 메모리 내용을 변경하려 한다면 컴파일 오류가 발생할 것이고 프로그래머는 실수를 빠르게 알 수 있을 것입니다. 위 내용에 대한 자세한 내용도 다음에 합니다. 입력 매개변수, 출력 매개변수에 대한 내용을 공부할 때 다시 하도록 하겠습니다.

 

2, 가변인자

가변인자를 사용하는 대표적인 함수가 printf(), scanf()함수입니다.

void main( )
{
    printf("hello!\n");             // 인자 하나(문자열)
    printf("%d\n", 10);             // 인자 둘 (문자열, 정수)
    printf("%d %d\n", 10, 20);       // 인자 셋 (문자열, 정수, 정수)
    printf("double : %lf\n", 2.35); // 인자 둘 (문자열, 실수)
    printf("%d + %d = %d\n", 10, 20, 30); // 인자 넷 (문자열, 정수, 정수, 정수)
}
  1. hello!
    10
    10 20
    double : 2.350000
    10 + 20 = 30

위 printf()함수의 인자를 보면 함수는 하나입니다. 하지만 인자들은 개수와 인자의 자료형이 서로 다릅니다. 이처럼 여러형태의 인자를 사용할 수 있는 함수를 가변인자 함수라 합니다.

 

우리도 printf()함수와 비슷한 가변인자 함수를 만들어 보도록 하겠습니다.

void Print(int n, ... )
{
}
void main( )
{
    Print( 1 );
    Print( 1 , 2);
    Print( 1 , 2, 3);
}

가변인자 함수는 위 예제 처럼 만듭니다. 컴파일 해 보면 문제 없이 잘 돌아갑니다.

가변인자 함수는 첫 번째 매개변수가 꼭 있어야하며 두번째 인자부터 ... 연산자를 사용할 수 있습니다.

첫 번째 인자가 없으면 함수 내부에서 인자들의 값을 찾을 수 없기 때문입니다.

가변인자 메커니즘은 함수에 인자들이 전달될 때 함수 호출 규칙에 따라 순서대로 절달된다는 것을 이용합니다.

아래 그림을 참고하세요. (이해가 어렵다면 사용자 함수절을 복습하세요)

 

 

 그래서 첫번째 인자 n을 이용하여 모든 인자 값들을 접근할 수 있습니다. &n이 12fe78이고 n의 크기가 4byte이므로 다음 인자 값 2는 주소 12fe7c에 존재하며 세번째 인자값 3은 12fe80에 존재합니다.

 

첫 번째 매개변수를 이용하면 모든 인자 값을 접근하고 출력할 수 있습니다.

void Print(int n, ... )
{
    int *pn = &n;

    for(int i = 0 ; i < 3 ; i++)
        printf("%3d\n", pn[i]);
}
void main( )
{
    Print( 1 , 2, 3);
}

  1. 1
  2. 2
  3. 3

그림을 이해했다면 결과는 쉽습니다.

 

 

 

 

보통 첫 번째 인자에 다음으로 들어오는 인자들의 여러가지 정보(인자의 자료형이나 개수)를 담아 모든 인자들을 접근할 수 있습니다.

void Print(int n, ... )
{
    int *pn = &n;

    for(int i = 0 ; i <= n ; i++)
        printf("%5d", pn[i]);

    puts("");
}
void main( )
{
    Print( 0);

    Print( 2 , 100, 200);
    Print( 3 , 5, 6, 7);
    Print( 4 , 21, 22, 23, 24);

    Print( 5 , 50, 50, 50, 50, 50);
}

  1.     0
        2  100  200
        3    5    6    7
        4   21   22   23   24
        5   50   50   50   50   50

첫 번째 인자 n에 모든 인자의 개수를 전달하여 모든 값을 출력합니다.

현재까지 예제는 모두 4byte int형 인자의 크기를 갖는다는 전제하에 작성한 코드입니다. 만약 함수로 전달되는 인자들의 자료형이 서로 다르다면 구현하기 쉽지 않습니다. 그래서 가변인자를 조금 더 쉽게 사용할 수 있도록 C언어는 매크로 함수를 제공합니다.

 

그래서 위 예제는 아래 처럼 매크로 함수를 이용하여 바꿀 수 있습니다.

#include <stdio.h>
#include <stdarg.h>

void Print(int n, ... )
{
    va_list pn;
    va_start(pn, n);
    for(int i = 0 ; i < n ; i++)

        printf("%5d", va_arg(pn, int) );
    puts("");
    va_end(pn);
}
void main( )
{
    Print( 0);
    Print( 2 , 100, 200);
    Print( 3 , 5, 6, 7);
    Print( 4 , 21, 22, 23, 24);
    Print( 5 , 50, 50, 50, 50, 50);
}


  1.   100  200
        5    6    7
       21   22   23   24
       50   50   50   50   50

va_list는 포인터 변수를 pn을 선언하고 va_start()함수는 pn 포인터 변수를 n인자 다음을 가리키도록 하고 va_arg()함수는 pn을 int만큼 이동시키고 현재 위치의 인자 값을 반환합니다. va_end()함수는 pn 포인터를 NULL로 만듭니다.

 

마지막으로 아래 예제를 완성해 보세요.

void main( )
{
    Print("Hello! \n");

    Print("Hello! %d %d \n", 10, 20);
    Print("Hello! %f %f \n"), 2.5, 3.5 );

}


'Programming > C,C++' 카테고리의 다른 글

간단한 thread 예제  (0) 2017.04.16
C++, const with function [펌]  (0) 2017.04.07
Stack (Double Linked), C++  (0) 2017.04.07
Queue (Double Linked), C++  (0) 2017.04.06
new delete + Heap overruns checker  (0) 2017.04.05
Posted by 루나s
,