C에서 'char**'를 'const char* const*'로 변환할 수 없는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/78125

문제

다음 코드 조각은 (정확하게) C에서 경고를 제공하고 C++에서 오류를 제공합니다(각각 gcc & g++ 사용, 버전 3.4.5 및 4.2.1에서 테스트됨).MSVC는 신경 쓰지 않는 것 같습니다):

char **a;
const char** b = a;

나는 이것을 이해하고 받아들일 수 있다.
이 문제에 대한 C++ 해결책은 b를 const char * const *로 변경하는 것입니다. 이렇게 하면 포인터 재할당을 허용하지 않고 const 정확성을 우회하는 것을 방지할 수 있습니다(C++ FAQ).

char **a;
const char* const* b = a;

그러나 순수 C에서는 수정된 버전(const char * const * 사용)이 여전히 경고를 표시하며 그 이유를 이해할 수 없습니다.캐스트를 사용하지 않고 이 문제를 해결할 수 있는 방법이 있나요?

명확히 하기 위해:
1) C에서 경고가 생성되는 이유는 무엇입니까?완전히 const로부터 안전해야 하며 C++ 컴파일러는 이를 그렇게 인식하는 것 같습니다.
2) 이 char**를 매개변수로 받아들이는 동시에 그것이 가리키는 문자를 수정하지 않을 것이라고 말하면서(그리고 컴파일러가 시행하도록 하는) 올바른 방법은 무엇입니까?예를 들어, 함수를 작성하고 싶다면 다음과 같습니다.

void f(const char* const* in) {
  // Only reads the data from in, does not write to it
}

그리고 char**에서 이를 호출하고 싶었습니다. 매개변수의 올바른 유형은 무엇입니까?

편집하다:답변을 주신 분들께 감사드립니다. 특히 질문에 답변을 주거나 제 답변에 후속 조치를 취해주신 분들께 감사드립니다.

내가 하고 싶은 일은 가능 여부를 떠나 캐스트 없이는 할 수 없다는 답변을 받아들였습니다.

도움이 되었습니까?

해결책

나는 몇 년 전에 이와 같은 문제를 겪었고 그것은 나를 끝없이 짜증나게 했습니다.

C의 규칙은 더 간단하게 설명됩니다(예:변환과 같은 예외는 나열하지 않습니다. char** 에게 const char*const*).결과적으로 그것은 허용되지 않습니다.C++ 표준에는 이와 같은 경우를 허용하는 더 많은 규칙이 포함되었습니다.

결국 C 표준의 문제일 뿐입니다.다음 표준(또는 기술 보고서)에서 이 문제가 해결되기를 바랍니다.

다른 팁

호환 가능한 것으로 간주하려면 소스 포인터가 바로 앞 간접 참조 수준에서 const여야 합니다.따라서 GCC에서는 다음과 같은 경고가 표시됩니다.

char **a;
const char* const* b = a;

하지만 다음은 그렇지 않습니다.

const char **a;
const char* const* b = a;

또는 다음과 같이 캐스팅할 수 있습니다.

char **a;
const char* const* b = (const char **)a;

언급한 대로 f() 함수를 호출하려면 동일한 캐스트가 필요합니다.내가 아는 한, 이 경우 암시적 변환을 수행할 수 있는 방법은 없습니다(C++ 제외).

> 그러나 순수 C에서는 여전히 경고가 표시되며 왜 그런지 모르겠습니다.

이미 문제를 확인했습니다. 이 코드는 const가 정확하지 않습니다."Const 올바른"은 const_cast 및 const를 제거하는 C 스타일 캐스트를 제외하고는 해당 const 포인터나 참조를 통해 const 개체를 수정할 수 없음을 의미합니다.

const-correctionness의 가치 - const는 대부분 프로그래머 오류를 감지하기 위해 존재합니다.무언가를 const로 선언하면 수정해서는 안 된다고 생각하는 것입니다. 또는 적어도 const 버전에만 액세스할 수 있는 사용자는 이를 수정할 수 없어야 합니다.고려하다:

void foo(const int*);

선언된 대로 foo에는 없습니다. 허가 인수가 가리키는 정수를 수정합니다.

게시한 코드가 왜 const-올바르지 않은지 확실하지 않은 경우 HappyDude의 코드와 약간 다른 다음 코드를 고려해 보세요.

char *y;

char **a = &y; // a points to y
const char **b = a; // now b also points to y

// const protection has been violated, because:

const char x = 42; // x must never be modified
*b = &x; // the type of *b is const char *, so set it 
         //     with &x which is const char* ..
         //     ..  so y is set to &x... oops;
*y = 43; // y == &x... so attempting to modify const 
         //     variable.  oops!  undefined behavior!
cout << x << endl;

비-const 유형은 명시적인 캐스트 없이 데이터 유형에서 'const'를 우회하는 것을 방지하기 위해 특정 방식으로 const 유형으로만 변환할 수 있습니다.

처음에 const로 선언된 객체는 특히 특별합니다. 컴파일러는 객체가 절대 변경되지 않는다고 가정할 수 있습니다.그러나 형변환 없이 'b'에 'a' 값을 할당할 수 있으면 실수로 const 변수를 수정하려고 시도할 수 있습니다.이렇게 하면 컴파일러에 요청한 검사가 중단되어 해당 변수 값을 변경할 수 없게 될 뿐만 아니라 컴파일러 최적화도 중단될 수 있습니다!

일부 컴파일러에서는 '42'가 인쇄되고, 일부 컴파일러에서는 '43'이 인쇄되며, 다른 컴파일러에서는 프로그램이 중단됩니다.

편집-추가:

행복한 친구:귀하의 의견이 정확합니다.C 언어나 사용 중인 C 컴파일러는 const char * const *를 C++ 언어가 처리하는 것과 근본적으로 다르게 처리합니다.아마도 이 소스 라인에 대해서만 컴파일러 경고를 침묵시키는 것을 고려해 보십시오.

편집-삭제: 오타가 제거됨

이는 짜증나는 일이지만 다른 수준의 리디렉션을 추가하려는 경우 포인터 간 포인터로 푸시다운하기 위해 다음을 수행할 수 있는 경우가 많습니다.

char c = 'c';
char *p = &c;
char **a = &p;

const char *bi = *a;
const char * const * b = &bi;

약간 다른 의미가 있지만 일반적으로 실행 가능하며 캐스트를 사용하지 않습니다.

적어도 MSVC 14(VS2k5) 및 g++ 3.3.3에서는 char**를 const char * const *로 암시적으로 캐스팅할 때 오류가 발생할 수 없습니다.GCC 3.3.3에서는 경고가 표시되는데, 이것이 올바른지 확실하지 않습니다.

테스트.c:

#include <stdlib.h> 
#include <stdio.h>
void foo(const char * const * bar)
{
    printf("bar %s null\n", bar ? "is not" : "is");
}

int main(int argc, char **argv) 
{
    char **x = NULL; 
    const char* const*y = x;
    foo(x);
    foo(y);
    return 0; 
}

C 코드로 컴파일하여 출력:cl /TC /W4 /Wp64 테스트.c

test.c(8) : warning C4100: 'argv' : unreferenced formal parameter
test.c(8) : warning C4100: 'argc' : unreferenced formal parameter

C++ 코드로 컴파일하여 출력:cl /TP /W4 /Wp64 테스트.c

test.c(8) : warning C4100: 'argv' : unreferenced formal parameter
test.c(8) : warning C4100: 'argc' : unreferenced formal parameter

gcc로 출력:gcc -벽 테스트.c

test2.c: In function `main':
test2.c:11: warning: initialization from incompatible pointer type
test2.c:12: warning: passing arg 1 of `foo' from incompatible pointer type

g++로 출력:g++ -벽 테스트.C

출력 없음

나는 const 키워드가 데이터가 변경될 수 없거나 일정하다는 것을 의미하는 것이 아니라 데이터가 읽기 전용으로 처리된다는 것을 확신합니다.이걸 고려하세요:

const volatile int *const serial_port = SERIAL_PORT;

유효한 코드입니다.휘발성과 const가 어떻게 공존할 수 있나요?단순한.휘발성은 컴파일러에게 데이터를 사용할 때 항상 메모리를 읽도록 지시하고, const는 serial_port 포인터를 사용하여 메모리에 쓰려고 할 때 컴파일러에게 오류를 생성하도록 지시합니다.

const가 컴파일러의 최적화 프로그램에 도움이 됩니까?아니요.별말씀을요.캐스팅을 통해 데이터에 불변성을 추가하거나 제거할 수 있기 때문에 컴파일러는 불변 데이터가 실제로 상수인지 알아낼 수 없습니다(캐스트는 다른 변환 단위에서 수행될 수 있으므로).C++에는 문제를 더욱 복잡하게 만드는 가변 키워드도 있습니다.

char *const p = (char *) 0xb000;
//error: p = (char *) 0xc000;
char **q = (char **)&p;
*q = (char *)0xc000; // p is now 0xc000

실제로 읽기 전용인 메모리(예: ROM)에 쓰려고 하면 어떻게 되는지가 표준에 전혀 정의되어 있지 않을 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top