변수 키워드에 대해 const 키워드를 언제 그리고 어떤 목적으로 C에서 사용해야합니까?


58

여기 에서 내 코드를 검토 하는 동안 const키워드 사용 문제 가 발생했습니다. 변수에서 읽기 전용 동작을 구현하는 데 사용된다는 것을 알고 있습니다.

유용 할 수있는 다양한 상황이 무엇인지 혼란 스럽습니다.

  • 함수 프로토 타입에서 명확성을 위해 사용해야합니까?
  • 코드 개발시 보안 수단으로 사용해야합니까?
  • 런타임 상수를 선언하기 위해 다양한 함수 범위에서 사용해야합니까?
  • 전혀 사용해야합니까?

이 질문은 내가 직면하고있는 혼란의 예일뿐입니다. 일반적인 혼란은

  • constC 프로그래밍에서 키워드를 언제 사용해야 합니까?
  • C에서이 키워드를 사용하여 얻을 수있는 다양한 유형의 이점은 무엇입니까?
  • const키워드 사용에 대한 단점이 있습니까?


이 질문은 내 질문에 대한 모든 질문으로 인해 너무 광범위 할 수 있다고 지적되었습니다. 나는이 질문들이 단지 주요 질문에 관한 혼란을 명확히하기위한 것임을 명확히하고 싶었다.

변수 키워드에 대해 const 키워드를 언제 그리고 어떤 목적으로 C에서 사용해야합니까?

또한 다음과 같이 표현할 수 있습니다.

constC`에서 키워드의 장단점을 올바르게 사용 합니다.


폐쇄 된 투표의 경우 왜의 카테고리에 속하지 않는지 설명하십시오 Specific issues with software development. 나는 매우 구체적입니다.
Aseem Bansal

같은 게시물에 여러 질문을했기 때문에 귀하의 질문이 너무 광범위 카테고리에 속 한다고 생각합니다. "응답 범위를 좁히거나 몇 문단에서 대답 할 수있는 문제를 분리합니다."
Robert Harvey

1
@RobertHarvey이 모든 질문은 혼란을 설명하기위한 것입니다. 내 유일한 질문은이 질문의 제목으로 남아 있습니다. 이에 대한 좋은 답변은 이러한 모든 관련 질문을 다룰 것입니다. 그래서 그것은 남아 있습니다 specific issue. constC`에서 키워드의 장단점을 올바르게 사용 합니다.
Aseem Bansal

@RobertHarvey 지금은 나아 졌습니까?
Aseem Bansal

답변:


64

코드를 검토 할 때 다음 규칙을 적용합니다.

  • const함수가 가리키는 데이터를 수정하거나 해제하지 않는 경우 참조로 전달 된 함수 매개 변수에 항상 사용 하십시오.

    int find(const int *data, size_t size, int value);
  • 항상 const#define 또는 열거 형을 사용하여 정의 할 수있는 상수에 사용하십시오. 컴파일러는 결과적으로 ROM (읽기 전용 메모리)에 데이터를 배치 할 수 있습니다 (링커는 종종 임베디드 시스템에서이 목적을 위해 더 나은 도구 임).

    const double PI = 3.14;
  • value로 전달 된 매개 변수 에 대해 함수 프로토 타입 에서 const를 사용하지 마십시오 . 그것은 의미가 없으며 따라서 단지 '잡음'입니다.

    // don't add const to 'value' or 'size'
    int find(const int *data, size_t size, const int value); 
  • 적절한 const volatile경우 프로그램에서 변경할 수 없지만 여전히 변경 될 수있는 위치 에서 사용 하십시오. 하드웨어 레지스터는 일반적인 유스 케이스입니다 (예 : 장치 상태를 반영하는 상태 레지스터).

    const volatile int32_t *DEVICE_STATUS =  (int32_t*) 0x100;

다른 용도는 선택 사항입니다. 예를 들어, 함수 구현 내의 함수에 대한 매개 변수 는 const로 표시 될 수 있습니다.

// 'value' and 'size can be marked as const here
int find(const int *data, const size_t size, const int value)  
{
     ... etc

또는 함수 반환 값 또는 얻은 다음 절대로 변경하지 않는 계산 :

char *repeat_str(const char *str, size_t n) 
{
    const size_t len = strlen(str);
    const size_t buf_size = 1 + (len * n);
    char *buf = malloc(buf_size);
    ...

이러한 용도 const는 변수를 변경하지 않음을 나타냅니다. 변수가 저장되는 방법이나 위치를 변경하지 않습니다. 컴파일러는 변수가 변경되지 않았 음을 추가로 해결할 수 있지만 추가 const하면 변수 를 적용 할 수 있습니다. 이것은 독자를 돕고 안전성을 높이는 데 도움이 될 수 있습니다 (함수가 큰 차이를 만들 정도로 충분히 크거나 복잡하더라도 다른 문제가있을 수 있습니다). 편집-예. 중첩 된 루프와 길거나 유사한 변수 이름이 많은 200 줄의 밀도가 높은 코드화 된 함수는 특정 변수가 절대로 변경되지 않는다는 것을 알기 때문에 크게 이해하기 어려울 수 있습니다. 이러한 기능은 잘못 설계되거나 유지 관리되었습니다.


문제 const. 아마도 "const poisoning"이라는 용어를들을 것입니다. const함수 매개 변수에 추가 하면 'constness'가 전파 될 때 발생합니다 .

편집-const poisoning : 예를 들어 함수에서 :

int function_a(char * str, int n)
{
    ...
    function_b(str);
    ...
}

우리가 변경 한 경우 strconst, 우리는 그가 확인해야합니다 fuction_b도합니다 const. 등등 경우는 function_b를 전달 str에게 function_c이 많은 별도의 파일 / 모듈로 전달하면이 고통이 될 수 상상할 수 있듯이 등. 변경할 수없는 함수 (예 : 시스템 라이브러리)로 전파되면 캐스트가 필요합니다. 따라서 const기존 코드를 뿌리면 문제가 발생할 수 있습니다. 새 코드 const에서는 적절한 곳에서 일관되게 자격 을 얻는 것이 가장 좋습니다 .

더 교활한 문제 const는 원래 언어가 아니었다는 것입니다. 애드온 으로서는 적합하지 않습니다. 처음에는 두 가지 의미가 있습니다 (위의 규칙에서와 같이 "이것은 변경하지 않을 것입니다"와 "이것은 수정할 수 없습니다"를 의미합니다). 그러나 그 이상으로 위험 할 수 있습니다. 예를 들어,이 코드를 컴파일하고 실행하면 (컴파일러 / 옵션에 따라) 실행될 때 충돌이 발생할 수 있습니다.

const char str[] = "hello world\n";
char *s = strchr(str, '\n');
*s = '\0';

strchrchar*아닌을 반환합니다 const char*. 호출 매개 변수는 호출 매개 변수를로 캐스팅const 해야합니다 . 그리고이 경우 실제 읽기 전용 저장소 속성을 제거합니다. 편집 :-이것은 일반적으로 읽기 전용 메모리의 var에 적용됩니다. 'ROM'은 일반적인 ROM에서 실행되는 프로그램의 코드 섹션에서와 같이 물리적 ROM뿐만 아니라 쓰기 방지 된 메모리를 의미합니다.char*

많은 표준 라이브러리 함수는 같은 방식으로 작동하므로주의하십시오. 실제 상수 가있을 때 (즉, ROM에 저장 됨) 그 일관성을 잃지 않도록주의해야합니다.


실제로 두 가지 의미가 없습니다. " 나는 이것을 바꾸지 않겠다 "는 의미 입니다. 예를 들어 const volatile변수 를 갖는 것이 완벽하게 유효 합니다.
detly

2
함수 매개 변수에는 해당하지만 파일 범위의 상수 (예 : const변수는 실제로 읽기 전용 임)에 해당합니다. const"이것은 수정할 수 없습니다 "라고 말합니다 . 반면 const volatile에 A 는 " 수정할 수 없지만 변경 될 수 있습니다"라고 말합니다. 대답에 휘발성 물질에 대한 언급을 추가하겠습니다.
윌리엄 모리스

ROM에 넣는 것이 컴파일러에게 지시한다는 생각만으로 귀하의 의견에 동의하지 않습니다. 즉 정의되지 않은 동작에 대한 런타임 가드의 일종을 의미한다 (예. 어떻게 든을 통해 const를 수정) "나는이 변경 이유 등의 오해로 이어질 수, const비를 통해 변수를 const포인터"(SO에 대한 일반적인 질문과 다른 모든 C 포럼 !). 전반적인 나는이 답변을 좋아하지만 :)
detly

"Put this in ROM"은 정확하지 않습니다 (간결하지만 :-)- "이것은 수정할 수 없습니다"로 변경합니다. 더 정확합니다. 귀하의 의견에 감사드립니다.
윌리엄 모리스

이것은 훌륭한 개요입니다. 저는 “이것은 수정할 수 없습니다”와“이것은 수정할 수 없습니다”의 차이점 인 읽기 const전용 데이터데이터 에 대한 읽기 전용 를 모두 선언 하는 것으로 표현하고 싶습니다 .
존 퍼디

8

일반적으로 모든 프로그래밍 언어에서의 사용을 권장 const하거나 해당 수정 이후

  • 발신자에게 전달한 내용이 변경되지 않음을 명확히 할 수 있습니다.
  • 컴파일러는 매개 변수가 변경 될 수있는 경우에만 관련된 특정 항목을 생략 할 수 있음을 알고 있으므로 잠재적 인 속도 개선
  • 실수로 값을 변경하지 않도록 보호

1

예, 기본적으로 TheLQ의 답변입니다.

프로그래머를위한 보안 수단이므로 변수를 수정하지 말고 변수를 수정할 수있는 함수를 호출하지 마십시오. 배열 또는 구조에서 const 지정자는 내용의 값이 수정되지 않으며 컴파일러조차도 그렇게 할 수 없음을 나타냅니다. 그러나 캐스트만으로도 변수 값을 쉽게 변경할 수 있습니다.

필자가 일반적으로 본 것처럼 코드에서 상수 값을 추가하고 특정 함수를 호출하면 배열이나 구조가 수정되지 않음을 나타내는 데 주로 사용됩니다. 이 마지막 부분은 배열이나 구조를 수정하는 함수를 호출 할 때 원래 버전을 유지하기 위해 변수의 사본을 작성한 다음 함수에 전달하기 때문에 중요합니다. 그렇지 않은 경우 분명히 사본이 필요하지 않으므로 예를 들어 변경할 수 있습니다.

int foo(Structure s);

int foo(const Structure * s);

복사 오버 헤드가 발생하지 않습니다.

추가하기 위해 C에는 const 지정자와 함께 특정 규칙이 있습니다. 예를 들어

int b = 1;
const int * a = &b;

와 같지 않다

int b = 1;
int * const a = &b;

첫 번째 코드에서는 a를 수정할 수 없습니다. 두 번째 경우 포인터는 일정하지만 그 내용은 다르므로 컴파일러는 * a = 3;컴파일러 오류없이 말할 수 있지만 a다른 것을 참조 할 수는 없습니다 .


0

TheLQ의 진술에 따라 :

프로그래머 팀과 함께 작업 할 때 선언 const하는 것은 변수가 수정되어서는 안된다는 것을 나타내는 좋은 방법입니다. 그런 의미에서 유용하며 많은 두통을 줄일 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.