const 포인터의 요점은 무엇입니까? 함수 내에서 호출자의

const 값에 대한 포인터가 아니라 const 포인터 자체에 대해 이야기하고 있습니다.

나는 매우 기본적인 것들을 넘어서 C와 C ++를 배우고 있으며 오늘까지 포인터가 함수에 가치에 의해 전달된다는 것을 깨달았습니다. 이것은 함수 내에서 호출자의 원래 포인터에 영향을 미치지 않고 복사 된 포인터가 다른 값을 가리 키도록 할 수 있음을 의미합니다.

따라서 함수 헤더가 갖는 요점은 무엇입니까?

void foo(int* const ptr);

그러한 함수 안에서는 ptr이 const이기 때문에 다른 것을 가리킬 수 없으며 수정하기를 원하지 않지만 다음과 같은 함수는 다음과 같습니다.

void foo(int* ptr);

작업도 마찬가지입니다! 어쨌든 포인터가 복사되고 사본을 수정하더라도 호출자의 포인터는 영향을받지 않기 때문입니다. const의 장점은 무엇입니까?



답변

const 매우 중요한 C ++ 개념을 추구하는 데 사용해야하는 도구입니다.

컴파일러가 의미하는 바를 적용하도록하여 런타임이 아닌 컴파일 타임에 버그를 찾으십시오.

기능이 변경되지 않더라도 추가를 const하면 의도하지 않은 작업을 수행 할 때 컴파일러 오류가 발생합니다. 다음 오타를 상상해보십시오.

void foo(int* ptr)
{
    ptr = 0;// oops, I meant *ptr = 0
}

을 사용 int* const하면 값을로 변경하기 때문에 컴파일러 오류가 발생합니다 ptr. 일반적으로 구문을 통해 제한을 추가하는 것이 좋습니다. 너무 많이 들지 마십시오. 예를 들어 대부분의 사람들이 귀찮게하지 않는 경우 const입니다.


답변

더 많은 컴파일러 검사를 가능하게하기 때문에 인수 사용한다는 점을 지적 const합니다. 실수로 함수 내부에서 인수 값을 실수로 다시 할당하면 컴파일러가 물립니다.

나는 변수를 거의 재사용하지 않고 새로운 값을 보유하기 위해 새로운 변수를 만드는 것이 더 깨끗합니다. 따라서 본질적으로 모든 변수 선언은 다음 const과 같습니다 (루프 변수와 같은 일부 경우 제외)const 코드가 작동하지 못하게하는 )입니다.

이것은 함수 정의 에서만 의미 가 있습니다. 그것은 사용자에게 보이는 선언 에 속하지 않습니다 . 그리고 사용자는 내가 사용하는지 신경 쓰지 않습니다.const 함수 내부의 매개 변수에 .

예:

// foo.h
int frob(int x);
// foo.cpp
int frob(int const x) {
   MyConfigType const config = get_the_config();
   return x * config.scaling;
}

인수와 지역 변수가 모두 어떻게되는지 확인하십시오 const. 없는 둘 필요 하지만, 조금이라도 큰 기능이 반복적으로 실수에서 저를 저장하고있다.


답변

당신의 질문은 좀 더 일반적인 것을 만집니다 : 함수 인수는 const이어야합니까?

포인터와 같은 값 인수의 constness는 구현 세부 사항 이며 함수 선언의 일부를 형성 하지 않습니다 . 이것은 당신의 기능이 항상 이것임을 의미합니다 :

void foo(T);

함수 범위 인수 변수를 가변 또는 일정한 방식으로 사용하고자하는지 여부 는 전적으로 함수 구현 자 에게 달려 있습니다.

// implementation 1
void foo(T const x)
{
  // I won't touch x
  T y = x;
  // ...
}

// implementation 2
void foo(T x)
{
  // l33t coding skillz
  while (*x-- = zap()) { /* ... */ }
}

따라서 간단한 규칙 const에 따라 선언 (헤더)에 넣지 말고 변수를 수정하지 않으려는 경우 정의 (구현)에 넣으십시오.


답변

최상위 const 한정자는 선언에서 삭제되므로 질문의 선언은 정확히 동일한 함수를 선언합니다. 반면, 정의 (구현)에서 컴파일러는 포인터를 const로 표시하면 함수 본문 내에서 수정되지 않았는지 확인합니다.


답변

당신이 옳습니다. 발신자에게는 전혀 차이가 없습니다. 그러나 함수 작성자에게는 안전망이 될 수 있습니다. “알겠습니다.이 점을 잘못 지적하지 않아야합니다.” 매우 유용하지는 않지만 쓸모가 없습니다.

기본적으로 int const the_answer = 42프로그램에 있는 것과 같습니다 .


답변

에 많이있다 const키워드 것이 있으며 다소 복잡한 키워드입니다. 일반적으로 프로그램에 많은 const를 추가하는 것은 좋은 프로그래밍 관행으로 간주되고 웹에서 “const correctness”를 검색하면 이에 대한 많은 정보를 찾을 수 있습니다.

const 키워드는 소위 “유형 한정자”이고 다른 키워드는 volatileand restrict입니다. 최소한 휘발성은 const와 같은 (혼란스러운) 규칙을 따릅니다.


먼저 const 키워드는 두 가지 목적을 제공합니다. 가장 확실한 방법은 데이터 (및 포인터)를 읽기 전용으로 만들어서 의도적이거나 우발적 인 오용으로부터 보호하는 것입니다. const 변수를 수정하려는 시도는 컴파일 타임에 컴파일러에 의해 발견됩니다.

그러나 읽기 전용 메모리가있는 시스템의 또 다른 목적도 있습니다. 즉, 특정 변수가 이러한 메모리 내에 할당되도록하는 것입니다. 예를 들어 EEPROM이거나 플래시 일 수 있습니다. 이를 비 휘발성 메모리 NVM이라고합니다. NVM에 할당 된 변수는 여전히 const 변수의 모든 규칙을 따릅니다.

const키워드 를 사용하는 방법에는 여러 가지가 있습니다 .

상수 변수를 선언하십시오.

이것은 다음과 같이 수행 할 수 있습니다

const int X=1; or
int const X=1;

이 두 형식은 완전히 같습니다 . 후자의 스타일은 잘못된 스타일로 간주되므로 사용하지 않아야합니다.

두 번째 행이 잘못된 스타일로 간주되는 이유는 아마도 정적 및 extern과 같은 “스토리지 클래스 지정자”도 실제 유형 뒤에 선언 될 수 있기 때문일 수 있습니다 .int static 사용되지 않는 기능으로 표시되는 등 그러나 저장소 클래스 지정자에 대해 이렇게 C위원회에 의해 (ISO 9899 N1539 초안, 6.11.5). 따라서 일관성을 유지하기 위해 형식 한정자를 해당 방식으로 작성해서는 안됩니다. 독자를 혼란스럽게하는 것 외에는 다른 목적이 없습니다.

상수 변수에 대한 포인터를 선언하십시오.

const int* ptr = &X;

이는 ‘X’의 내용을 수정할 수 없음을 의미합니다. 이것은 “const correctness”에 대한 함수 매개 변수의 일부로 이와 같은 포인터를 선언하는 일반적인 방법입니다. ‘X’는 실제로 const로 선언 될 필요가 없으므로 변수 일 수 있습니다. 즉, 변수를 항상 “업그레이드”하여 const로 만들 수 있습니다. 기술적으로 C는 명시 적 타입 캐스트에 의해 const에서 일반 변수로 다운 그레이드 할 수 있지만 그렇게하는 것은 나쁜 프로그래밍으로 간주되며 컴파일러는 일반적으로 경고를합니다.

상수 포인터 선언

int* const ptr = &X;

이것은 포인터 자체 가 일정 하다는 것을 의미합니다 . 가리키는 내용은 수정할 수 있지만 포인터 자체는 수정할 수 없습니다. 이것은 많은 용도가 없으며, 포인터가 가리키는 포인터 (pointer-to-pointer)가 매개 변수로 함수에 전달되는 동안 주소가 변경되지 않도록하는 것과 같은 몇 가지가 있습니다. 다음과 같이 읽을 수없는 것을 작성해야합니다.

void func (int*const* ptrptr)

많은 C 프로그래머가 const와 *를 얻을 수 있을지 의문입니다. 나도 내가 할 수 없습니다 – 나는 GCC 확인했다. 이것이 좋은 프로그래밍 관행으로 간주되지만 포인터 대 포인터의 구문을 거의 보지 못하는 이유입니다.

상수 포인터를 사용하여 포인터 변수 자체가 읽기 전용 메모리에 선언되도록 할 수도 있습니다. 예를 들어 포인터 기반 조회 테이블을 선언하여 NVM에 할당 할 수 있습니다.

물론 다른 답변에서 알 수 있듯이 상수 포인터를 사용하여 “정확도”를 강화할 수도 있습니다.

상수 데이터에 대한 상수 포인터 선언

const int* const ptr=&X;

이것은 위에서 설명한 두 가지 포인터 유형이며 모든 속성이 있습니다.

읽기 전용 멤버 함수 선언 (C ++)

이것은 C ++ 태그가 붙어 있기 때문에 클래스의 멤버 함수를 const로 선언 할 수 있다고 언급해야합니다. 이것은 함수가 호출 될 때 클래스의 다른 멤버를 수정할 수 없다는 것을 의미합니다. 이는 클래스의 프로그래머가 실수로 오류가 발생하는 것을 막을뿐 아니라 멤버 함수의 호출자에게 아무것도 엉망이되지 않음을 알려줍니다 그것을 호출하여. 구문은 다음과 같습니다.

void MyClass::func (void) const;

답변

… 오늘 포인터가 함수에 값으로 전달된다는 것을 깨달았습니다.

(imo) 실제로 기본값으로 이해가되지 않습니다. 더 합리적인 기본값은 재 할당 할 수없는 포인터 ( int* const arg) 로 전달하는 것 입니다. 즉, 인수로 전달 된 포인터가 암시 적으로 const로 선언 된 것을 선호했을 것입니다.

const의 장점은 무엇입니까?

장점은 인수가 가리키는 주소를 수정할 때 충분히 쉽고 때로는 명확하지 않다는 것입니다. 따라서 버그가 쉽게 정의되지 않을 때 버그가 발생할 수 있습니다. 주소를 변경하는 것은 비정형입니다. 주소를 수정하려는 경우 로컬 변수를 만드는 것이 더 명확합니다. 또한 원시 포인터 조작은 버그를 쉽게 도입 할 수있는 방법입니다.

따라서 불변 주소로 전달하고 인수가 가리키는 주소를 변경하려고 할 때 (비정상적인 경우) 사본을 만드는 것이 더 명확합니다.

void func(int* const arg) {
    int* a(arg);
    ...
    *a++ = value;
}

로컬을 추가하면 거의 무료이며, 가독성을 높이면서 오류 가능성을 줄입니다.

더 높은 수준에서 : 인수를 배열로 조작하는 경우 일반적으로 클라이언트가 인수를 컨테이너 / 컬렉션으로 선언하는 것이 더 명확하고 오류가 적습니다.

일반적으로 컴파일러가 행복하게 적용하는 부작용을 항상 인식하지는 못하므로 값, 인수 및 주소에 const를 추가하는 것이 좋습니다. 따라서 다른 여러 경우에 사용되는 const만큼 유용합니다 (예 : ‘왜 const를 값으로 선언해야합니까?’와 같은 질문입니다). 운 좋게도 우리는 또한 재 할당 할 수없는 참조를 가지고 있습니다.