programing

컨스턴스 포인터의 의미가 뭐야?

kingscode 2022. 9. 20. 21:43
반응형

컨스턴스 포인터의 의미가 뭐야?

저는 상수 값에 대한 포인터를 말하는 것이 아니라 상수 포인터 자체를 말하는 것입니다.

저는 기본적인 것 이상으로 C와 C++를 배우고 있으며, 오늘까지 포인터가 함수에 가치로 전달된다는 것을 깨달았습니다.즉, 함수 내에서 복사된 포인터가 발신자의 원래 포인터에 영향을 주지 않고 다른 값을 가리키도록 할 수 있습니다.

그렇다면 다음과 같은 함수 헤더가 있으면 어떤 의미가 있을까요?

void foo(int* const ptr);

이러한 함수 내에서는 ptr이 항상 다른 것을 가리키도록 할 수 없습니다.변경을 원하지 않지만 다음과 같은 함수입니다.

void foo(int* ptr);

포인터는 어쨌든 복사되고, 카피를 변경해도 발신자의 포인터는 영향을 받지 않기 때문에, 이 조작도 유효합니다.그럼 Const의 장점은 무엇일까요?

const는 매우 C++ 하기 위해 사용하는 도구입니다.

컴파일러가 의도하는 바를 실행하도록 함으로써 실행 시간이 아닌 컴파일 시간에 버그를 찾아냅니다.

「」를 추가해 주세요.const의도하지 않은 작업을 했을 때 컴파일러 오류가 발생합니다.이치노

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

「 」를 사용하고 int* const 값을 "Compiler " ( 에러가 발생합니다로 변경하면 오류가 ptr구문을 통해 제한을 추가하는 것은 일반적으로 좋은 일입니다., 대부분의 이 굳이 입니다.예를 들면, 대부분의 유저가 굳이 사용하지 않는 경우가 있습니다.const.

세상에는 많은 것이 있다.const키워드는 다소 복잡한 것입니다.일반적으로 프로그램에 많은 const를 추가하는 것은 좋은 프로그래밍 관행으로 간주됩니다.계속 수정하다

qualifier"입니다 키워드는 const "type qualifier"입니다.른른른른른른른volatile ★★★★★★★★★★★★★★★★★」restrict적어도 휘발성은 const와 같은 (혼란스러운) 규칙을 따릅니다.


먼저 const 키워드는 두 가지 목적으로 사용됩니다.가장 분명한 것은 데이터(및 포인터)를 읽기 전용으로 함으로써 의도적이거나 우발적인 오용으로부터 보호하는 것입니다.const 변수를 수정하려는 모든 시도는 컴파일 시 컴파일러에 의해 탐지됩니다.

그러나 읽기 전용 메모리를 탑재한 시스템에는 EEPROM이나 플래시 등 특정 변수가 메모리 내에 할당되어 있는지 확인하는 또 다른 목적이 있습니다.이들은 비휘발성 메모리, NVM으로 알려져 있습니다.NVM에 할당된 변수는 물론 const 변수의 모든 규칙을 따릅니다.

가 있습니다.const★★★★★★★★★★★★★★★★★★:

상수 변수를 선언합니다.

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

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

이 두 형태는 완전히 같다.후자의 스타일은 나쁜 스타일로 간주되므로 사용하지 마십시오.

두 번째 행이 잘못된 스타일로 간주되는 이유는 static이나 extern과 같은 "스토리지 클래스 지정자"도 실제 유형 뒤에 선언될 수 있기 때문일 수 있습니다.int static그러나 스토리지 클래스 지정자에 대해서는 C 위원회(ISO 9899 N1539 초안, 6.11.5)에 의해 사용되지 않는 기능으로 분류되어 있습니다.따라서 일관성을 위해 유형 한정자도 그런 식으로 작성해서는 안 됩니다.어쨌든 그것은 독자를 혼란시키는 것 외에는 다른 목적이 없다.

상수 변수에 대한 포인터를 선언합니다.

const int* ptr = &X;

즉, 'X'의 내용은 수정할 수 없습니다.이는 주로 "계속 정확성"을 위한 함수 매개변수의 일부로 이와 같은 포인터를 선언하는 일반적인 방법입니다.'X'는 실제로는 const로 선언할 필요가 없기 때문에 변수가 될 수 있습니다.즉, 변수를 항상 "업그레이드"하여 구성할 수 있습니다.엄밀히 말하면 C는 명시적인 타입캐스트에 의해 const에서 플레인 변수로 다운그레이드 할 수도 있지만, 그렇게 하면 잘못된 프로그래밍으로 간주되며 컴파일러는 보통 이에 대해 경고를 보냅니다.

상수 포인터 선언

int* const ptr = &X;

이는 포인터 자체가 일정함을 의미합니다.포인터가 가리키는 부분은 수정할 수 있지만 포인터 자체는 수정할 수 없습니다.이것은, 포인터 포인트 앳(포인터 투 포인터)가 함수에 파라메타로 건네지는 동안, 주소가 변경되지 않게 하는 등, 많은 용도가 없습니다.너무 읽기 어려운 내용을 다음과 같이 써야 합니다.

void func (int*const* ptrptr)

많은 C 프로그래머들이 const와 *를 바로 얻을 수 있을지 의문입니다.나는 내가 할 수 없다는 것을 안다 - 나는 GCC에 확인해야 했다.그래서 포인터 투 포인터의 구문은 거의 볼 수 없는 것 같습니다만, 좋은 프로그래밍 연습이라고 생각됩니다.

또한 포인터 변수 자체가 읽기 전용 메모리에 선언되도록 하기 위해 상수 포인터를 사용할 수도 있습니다. 예를 들어 일종의 포인터 기반 룩업 테이블을 선언하고 NVM에 할당할 수 있습니다.

물론, 다른 답변에서 알 수 있듯이, 상수 포인터는 "일정한 정확성"을 적용하기 위해 사용될 수도 있습니다.

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

const int* const ptr=&X;

이것은 위에서 설명한 두 가지 포인터 유형으로, 두 가지 모두의 속성을 모두 포함합니다.

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

이것은 C++ 태그가 붙어있기 때문에 클래스의 멤버 함수를 const로 선언할 수 있다는 것도 언급해야 합니다.이는 함수가 호출될 때 클래스의 다른 멤버를 수정할 수 없음을 의미하며, 이는 클래스의 프로그래머가 우발적인 오류를 방지하는 동시에 호출함으로써 멤버 함수에 대해 호출자에게 아무것도 망치지 않음을 알려줍니다.구문은 다음과 같습니다.

void MyClass::func (void) const;

저는 꼭 사용하려고 합니다. const더 함수 .arguments는 다음과 같습니다.함수 내에서 실수로 인수 값을 재할당하면 컴파일러가 나를 공격합니다.

변수를 재사용하는 경우는 거의 없습니다.새로운 값을 보유하기 위해 새로운 변수를 작성하는 것이 보다 명확하기 때문에 기본적으로 모든 변수 선언은 다음과 같습니다.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 수식자는 선언에서 폐기되므로 질문의 선언은 동일한 함수를 선언합니다.한편, 정의(실장)에서 컴파일러는 포인터를 const로 마크하면 함수 본문 내에서 수정되지 않음을 확인합니다.

네 말이 맞아, 전화를 건 사람에겐 전혀 차이가 없어.그러나 이 함수의 작성자에게는 "좋아, 내가 이 점을 잘못 짚지 않도록 해야겠어"라는 안전망이 될 수 있다.아주 유용하진 않지만, 쓸모없지도 않아요.

으로는 '이렇게 하다'는 것과 int const the_answer = 42를 참조해 주세요.

당신의 질문은 좀 더 일반적인 것에 관한 것입니다.함수 인수는 계속해야 합니까?

값 인수의 항상성은 (포인터와 같이) 구현 세부 사항이며 함수 선언의 일부를 형성하지 않습니다.즉, 기능은 항상 다음과 같습니다.

void foo(T);

functions-scope 인수변수를 가변으로 사용할지, 일정한 방법으로 사용할지는 함수 구현자에게 전적으로 달려 있습니다.

// 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는 많은 것을 검출합니다.실행 시간이 아닌 컴파일 시 오류가 발생합니다.

읽기 전용 16비트 주변 칩 레지스터는 다음과 같습니다.

static const unsigned short *const peripheral = (unsigned short *)0xfe0000UL;

그러면 어셈블리 언어를 사용하지 않고도 하드웨어 레지스터를 쉽게 읽을 수 있습니다.

input_word = *peripheral;

...오늘 저는 포인터가 함수에 값별로 전달된다는 것을 깨달았습니다.그것은 일리가 있습니다.

(imo) 디폴트로는 의미가 없습니다.보다 알기 쉬운 디폴트로는 passing non-explacable pointer).int* const arg즉, 인수로 전달된 포인터가 암묵적으로 const로 선언되는 것을 선호합니다.

그럼 Const의 장점은 무엇일까요?

그 장점은 인수가 가리키는 주소를 변경할 때 충분히 쉽고 때로는 불분명하다는 것입니다.그래서 쉽게 변하지 않을 때 버그를 도입할 수 있습니다.주소 변경은 이례적입니다.주소를 수정하려면 로컬 변수를 만드는 것이 더 쉽습니다.또한 원시 포인터 조작은 버그를 발생시키는 쉬운 방법입니다.

따라서 인수가 가리키는 주소를 변경하고 싶을 때는 불변의 주소로 전달하고 복사본을 만드는 것이 더 쉽습니다.

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

로컬은 사실상 무료이며 오류 발생 가능성을 줄이고 가독성을 향상시킵니다.

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

일반적으로 값, 인수, 주소에 const를 추가하는 것은 좋은 생각입니다.왜냐하면 당신은 항상 부작용을 깨닫지 못하기 때문입니다.컴파일러는 이를 기쁘게 시행합니다.따라서 다른 몇 가지 사례에서 사용된 것과 마찬가지로 const도 유용합니다(예를 들어 "Why I declarate values const?"와 유사한 질문입니다). 다행히 참조도 있으므로 재할당될 수 없습니다.

int iVal = 10; int *const ipPtr = &iVal;

일반 const 변수와 마찬가지로 const 포인터는 선언 시 값으로 초기화해야 하며 값은 변경할 수 없습니다.

즉, const 포인터는 항상 같은 값을 가리킵니다.위의 경우 ipPtr은 항상 iVal 주소를 가리킵니다.단, 가리키는 값은 여전히 일정하지 않기 때문에 포인터의 참조를 해제하여 가리키는 값을 변경할 수 있습니다.

*ipPtr = 6; // 허용됨, pnPtr이 비정수 int를 가리키므로

포인터뿐만 아니라 다른 유형에 대해서도 같은 질문을 할 수 있습니다.

/* Why is n const? */
const char *expand(const int n) {
    if (n == 1) return "one";
    if (n == 2) return "two";
    if (n == 3) return "three";
    return "many";
}

문제는 변수를 함수에 대한 포인터 매개 변수뿐만 아니라 상수로 정의하는 이유에 대한 것입니다.함수, 멤버 변수 또는 로컬 변수에 대한 매개 변수인 경우 변수를 상수로 정의할 때와 동일한 규칙이 적용됩니다.

특정 경우 로컬 변수를 const로 선언할 때 다른 많은 경우처럼 기능적으로는 차이가 없지만 이 변수를 수정할 수 없다는 제한이 있습니다.

함수에 const 포인터를 전달하면 값에 의해 전달되므로 의미가 없습니다.일반적인 언어 디자인에서 허용되는 것들 중 하나일 뿐입니다.말이 안 된다고 해서 금지하는 것은 언어 사양을 만들 뿐입니다.더 큰.

함수 안에 있다면 당연히 다른 경우입니다.포인터가 가리키는 것을 변경할 수 없는 것은 코드를 명확하게 하는 어설션입니다.

컴파일러는 이 포인터를 변경할 수 없다는 것을 알고 함수 내에서 보다 적극적인 최적화를 실행할 수 있다는 장점이 있다고 생각합니다.

이하지 않은 참조를 할 수 ).void f(int *&p)하지만 이 경우 유용성이 다소 제한적이라는 점은 동의합니다.

따라서 const pointer의 적용성이 높은 예를 제시할 수 있다.동적 배열이 포함된 클래스가 있으며 사용자 액세스를 어레이에 전달하지만 포인터를 변경할 권한은 부여하지 않는다고 가정합니다.고려사항:

#include <new>
#include <string.h>

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const GetArray(){ return Array; }
};

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' '; //You can still modify the chars in the array, user has access
    Temp.GetArray()[1] = ' '; 
    printf("%s\n",Temp.GetArray());
}

그 결과:

데이터 ★★★★★★
를 넣다

하지만 이걸 시도하면:

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' ';
    Temp.GetArray()[1] = ' ';
    printf("%s\n",Temp.GetArray());
    Temp.GetArray() = NULL; //Bwuahahahaa attempt to set it to null
}

다음과 같은 것을 얻을 수 있습니다.

오류: 할당의 왼쪽 피연산자로 l값이 필요합니다//다시 Drat이 실패했습니다!

어레이의 내용은 수정할 수 있지만 어레이의 포인터는 수정할 수 없습니다.포인터를 사용자에게 전달할 때 포인터의 상태가 일관되게 유지되도록 하려면 좋습니다.단, 한 가지 단점이 있습니다.

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' ';
    Temp.GetArray()[1] = ' ';
    printf("%s\n",Temp.GetArray());
    delete [] Temp.GetArray(); //Bwuahaha this actually works!
}

포인터 자체를 수정할 수 없는 경우에도 포인터의 메모리 참조를 삭제할 수 있습니다.

따라서 메모리 참조가 항상 무언가를 가리키도록 하려면(IE는 수정되지 않으며, 현재 참조가 작동하는 방식과 유사) 매우 적합합니다.사용자에게 완전한 액세스 권한을 부여하고 이를 수정하려면 비일관성이 적합합니다.

편집:

GetArray()가 오른쪽 값 오퍼랜드이기 때문에 할당할 수 없다는 okorz001 코멘트를 기록한 후 코멘트는 완전히 맞지만 포인터에 대한 참조를 반환하는 경우(GetArray가 참조를 참조하는 것으로 가정함)에는 위의 코멘트가 계속 적용됩니다.다음은 예를 제시하겠습니다.

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const &GetArray(){ return Array; } //Note & reference operator
        char * &GetNonConstArray(){ return Array; } //Note non-const
};

int main()
{
    TestA Temp;
    Temp.GetArray() = NULL; //Returns error
    Temp.GetNonConstArray() = NULL; //Returns no error
}

에러가 발생하는 첫 번째 에러가 반환됩니다.

오류: 읽기 전용 위치 'Temp' 할당입니다.테스트 A:: GetArray()'

하지만 두번째는 그 밑에 잠재된 결과에도 불구하고 즐겁게 일어날 것이다.

분명히 '왜 포인터에 대한 참조를 반환하려고 하는가?'라는 질문이 제기될 것입니다.메모리(또는 데이터)를 문제의 원래 포인터에 직접 할당해야 하는 경우는 드물지만(예를 들어, 자신의 malloc/free 또는 새로운/free 프런트 엔드를 구축하는 경우 등), 이러한 경우에는 항상 참조가 되지 않습니다.const pointer에 대한 참조. const pointer를 보증하는 상황은 발생하지 않았습니다(반환 타입이 아닌 선언된 const reference variable?).

const pointer를 사용하는 함수가 있다고 가정합니다(const pointer를 사용하지 않는 함수와 비교).

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const &GetArray(){ return Array; }

        void ModifyArrayConst(char * const Data)
        {
            Data[1]; //This is okay, this refers to Data[1]
            Data--; //Produces an error. Don't want to Decrement that.
            printf("Const: %c\n",Data[1]);
        }

        void ModifyArrayNonConst(char * Data)
        {
            Data--; //Argh noo what are you doing?!
            Data[1]; //This is actually the same as 'Data[0]' because it's relative to Data's position
            printf("NonConst: %c\n",Data[1]);
        }
};

int main()
{
    TestA Temp;
    Temp.ModifyArrayNonConst("ABCD");
    Temp.ModifyArrayConst("ABCD");
}

const 오류는 다음과 같은 메시지를 생성합니다.

오류: 읽기 전용 매개 변수 'Data'의 감소

코멘트에 나타난 문제를 일으키고 싶지 않다면, 아마 우리는 그렇게 하고 싶지 않을 것이기 때문에 좋습니다.const 함수의 감소를 편집하면 다음과 같은 현상이 발생합니다.


B 정 : B

분명히 A는 'Data[1]'이지만 NonConst 포인터가 감소 작업을 허용했기 때문에 'Data[0]'으로 처리됩니다.const를 구현하면 다른 사람이 쓴 것처럼 잠재적인 버그가 발생하기 전에 잡습니다.

또 하나의 주요 고려사항은 const pointer를 의사 참조로 사용할 수 있다는 것입니다. 즉, 참조 포인트가 되는 것은 변경할 수 없다는 것입니다(혹시 이것이 구현된 방법일 수도 있음).고려사항:

int main()
{
    int A = 10;
    int * const B = &A;
    *B = 20; //This is permitted
    printf("%d\n",A);
    B = NULL; //This produces an error
}

컴파일 시도 시 다음 오류가 발생합니다.

오류: 읽기 전용 변수 'B' 할당

만약 A에 대한 지속적인 언급이 필요하다면 그것은 아마도 나쁜 일일 것이다. ifB = NULL, 해 줄 입니다.이치노*B가나다이것은 ints에서는 유용하게 보이지 않을 수 있지만, 그래픽 어플리케이션의 단일 스탠스가 있는 경우, 그것을 참조하는 변경할 수 없는 포인터가 필요한 경우, 그 포인터를 회송할 수 있는 경우를 고려해 주십시오.

용도는 가변적이지만(의도하지 않은 말장난은 용서), 올바르게 사용되므로 프로그래밍을 지원하는 또 다른 도구입니다.

포인터가 변하지 않기를 바라는 특별한 것은 없습니다. 의 상수 「」를 수 것과 ,int다음과 같은 이유로 일정한 포인터를 가질 수도 있습니다.당신은 지적된 것을 아무도 바꾸지 않도록 해야 합니다.C++ 참조는 어느 정도 이 문제를 해결하지만 포인터 동작은 C에서 상속됩니다.

이렇게 하면 함수 본문 내에서 코드가 포인터를 증가시키거나 감소시키는 것을 방지할 수 있다고 생각합니다.

: " " )
(1 (1) 를 선언하다.
DataType const varibleName;

 int const x;
    x=4; //you can assign its value only One time
(2)Declare a pointer to a constant variable
const dataType* PointerVaribleName=&X;
 const int* ptr = &X;
     //Here pointer variable refer contents of 'X' that is const Such that its cannot be modified
dataType* const PointerVaribleName=&X;
 int* const ptr = &X;
     //Here pointer variable itself is constant  Such that value of 'X'  can be modified But pointer can't be modified

언급URL : https://stackoverflow.com/questions/7715371/whats-the-point-of-const-pointers

반응형