본문 바로가기
프로그래밍 언어/C 언어

[C/C++] const 키워드

by 까망 하르방 2024. 10. 27.
반응형

const 키워드

C 언어에서 const는 읽기 전용 변수로 만들어주는 예약어일 뿐

완벽한 상수 기능을 갖도록 해주지 못했다.

const int n; // 초기값 오류 없음
char str[n]; // 배열의 요소 개수로 사용불가
int* p = &n;  // warning
*p = 10; // 변경 가능

 

 

하지만 C++에서는
완벽히 상수화(化) 시켜주는 예약어로 사용된다.
C++은 반드시 선언시 초기값을 선언하게 되었다.

const int n = 10; // must be initialized
char str[n]; // 배열의 요소 개수로 사용 가능

int* p = &n; // error (cannot convert from 'const int *' to 'int *’)
const int* cp = &n;
// *cp = 10; // 변경 불가

 

 

 포인터에 예약어 const의 적극적인 사용 권장

함수 이름에 const를 포함한 const 멤버함수는 컴파일 시간에 

멤버데이터의 변경을 검사(compile-error)할 수도 있게 하지만

const 개체가 안전하게 호출할 수 있는 멤버함수임을 표시하기도 하고 

코드의 가독성을 높이기 위한 적극적인 표현이기도 하다.

 

생성자함수, 소멸자함수, static멤버함수는 const멤버함수로 둘 수 없다.

ex) 생성자 함수에서 값을 대입(변경)할 수 있기에 생성자와 소멸자에서는 const 불가

int data = 5;

// 오직 data만 가리킬거야, 난 변하지 않아.
// 포인터 변수를 고정, 바로 초기화 해야 됨
// 가리키는 대상이 const인지 아닌지는 중요 X
// 다른 애를 가리킬 수 없음
int* const p = &data; 

// 읽기만 할거야 (가리키는 대상을 바꿀 수 없음)
// 포인터 변수가 가르키는 변수가 const 여부는 중요 X
const int * onlyread;

// 오직 data만을 가리키고 그 대상을 읽기만 할거야.
const int* const p = &data; 

const int cdata = 5;

// 가리키는 데이터는 const int(int const)형이야
// 읽기만 하는데 포인터 변수가 가르키는 대상이 const 변수다!
int const* icp = &cdata;

 

 

포인터 변수와 const 키워드

아래 두 구문은 차이가 존재합니다.

① const int *ptr = #
② int * const ptr = #
 
[첫번째]는 포인터 변수 ptr이 가리키는 변수에 저장된 값 변경을 허용하지 않는 것입니다.
하지만 변수 num 자체는 상수가 아니기 때문에 변경이 가능합니다.
즉, const 선언은 값 변경에 제한을 두지만 상수화 하는 것은 아닙니다.
int num = 20;
const int *ptr = #
*ptr = 30; // 포인터 변수를 이용한 실제 값 변경 시도시 컴파일 에러
num = 40; // num 자체가 상수는 아니기 때문에 변경 가능
 
[두번째] 경우는 포인터 변수를 상수화 시키는 경우로,
한번 주소 값이 저장되면 그 주소값 변경이 불가능합니다.
하지만 포인터 변수가 가리키기 시작한 변수는 변경할 수 있습니다.
int num = 20;
int* const ptr = #
int value = 30;

ptr = &value; // 컴파일 에러
*ptr = 40; // 컴파일 성공
 
두가지 const 형태를 동시에도 가능 
const int* const ptr = &num

*ptr = 20; // 컴파일 에러
ptr = &value; // 컴파일 에러
이때는, 포인터 변수의 변경도 안되고, 가리키고 있는 변수 값의 변경도 되지 않습니다.
(물론, num 변수 자체로 값 변경은 가능)
 
 
예시
#include <iostream>

using namespace std;

void sub_A(const int** a) // 읽기만 하겠다.
{
    // **a = 10; 읽기만 할 수 있어서 오류
}

void sub_B(int* const* b)
{
    int x = 10;

    **b = 11; // 가르키는 대상을 바꾸는것은 가능
    // *b = &x; // 다른 주소로 변경 불가
    // 만약 **b = 10 조차 불가능하게 하려면 (const int * const *b)로 사용하면 됨
}

int main(void)
{
    int n = 5, k = 6;
    
    // 가르키는 대상을 읽기만 하겠다.
    // 초기값 굳이 필요 x
    const int* cp;
    cp = &n;
    cp = &k; // 다른 주소로 변경 가능
    // *cp = 100; 값 변경은 불가
    cout << *cp << endl; // 값을 읽는것은 가능

    // 포인터를 고정하기 때문에 초기값 반드시 필요(n만을 가르키겠다)
    // 가르키는 대상이 const 타입일 필요는 없다.
    // 나중에 다른 변수의 주소 대입 불가 (q = &k;)
    int* const q = &n;

    sub_A(&cp);
    sub_B(&q);
}

 

#define vs const

const는 타입 Error 등을 막을 수 있으며

가독성 측면에서도 #define 보다 괜찮은 편이다.

하지만 메모리를 잡아먹기 때문에 메모리 절약 측면에서는 #define이 나은 편

한편으로 #define은 런타임 중 값 확인 하기 까다롭기도 하다.

 

 

📌 [C++] constexpr 키워드

 

[C++] constexpr 키워드

constexpr • 컴파일 시간에 결정되는 상수 값 • C++11 에서 도입된 문법 • 템플릿 인자로 사용 가능 • 상수식 계산, 배열 크기 정의 등 컴파일 시간에 최적화되는 코드 작성에 유용 const 키워드 비

zoosso.tistory.com

반응형

댓글