Programing

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

lottogame 2020. 12. 9. 07:41
반응형

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


다음 코드 조각은 (올바르게) 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_cast제거하는 C 스타일 캐스트를 제외하고는 해당 const 포인터 또는 참조를 통해 개체를 const수정할 수 없음을 의미 const합니다.

const-correctness 의 값은 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에서는, 다른 컴파일러에서는 프로그램이 충돌합니다.

편집-추가 :

HappyDude : 귀하의 의견이 있습니다. C 언어 또는 사용중인 C 컴파일러 const char * const *는 C ++ 언어가 처리하는 것과 근본적으로 다르게 처리합니다. 이 소스 행에 대해서만 컴파일러 경고를 침묵시키는 것을 고려해보십시오.


This is annoying, but if you're willing to add another level of redirection, you can often do the following to push down into the pointer-to-pointer:

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

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

It has a slightly different meaning, but it's usually workable, and it doesn't use a cast.


I'm not able to get an error when implicitly casting char** to const char * const *, at least on MSVC 14 (VS2k5) and g++ 3.3.3. GCC 3.3.3 issues a warning, which I'm not exactly sure if it is correct in doing.

test.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; 
}

Output with compile as C code: cl /TC /W4 /Wp64 test.c

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

Output with compile as C++ code: cl /TP /W4 /Wp64 test.c

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

Output with gcc: gcc -Wall test.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

Output with g++: g++ -Wall test.C

no output


I'm pretty sure that the const keyword does not imply the data can't be changed/is constant, only that the data will be treated as read-only. Consider this:

const volatile int *const serial_port = SERIAL_PORT;

which is valid code. How can volatile and const co-exist? Simple. volatile tells the compiler to always read the memory when using the data and const tells the compiler to create an error when an attempt is made to write to the memory using the serial_port pointer.

Does const help the compiler's optimiser? No. Not at all. Because constness can be added to and removed from data through casting, the compiler cannot figure out if const data really is constant (since the cast could be done in a different translation unit). In C++ you also have the mutable keyword to complicate matters further.

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

What happens when an attempt is made to write to memory that really is read only (ROM, for example) probably isn't defined in the standard at all.

참고URL : https://stackoverflow.com/questions/78125/why-cant-i-convert-char-to-a-const-char-const-in-c

반응형