2014-06-12 3 views
5

GLib에 관해 간단한 질문이 있습니다.GLib이이 함수에서 'const'를 사용하지 않는 이유는 무엇입니까?

static const char *words[] = { "one", "two", "three", NULL }; 

void main() { 
    puts(g_strjoinv("+", words)); 
} 

이 코드 인쇄 one+two+three :

나는 다음과 같은 코드가 있습니다. 문자열을 조인하는 GLib 함수를 사용합니다. 그 함수의

에게 signature은 다음과 같습니다

char *g_strjoinv (const char *separator, char **str_array); 

(. 정확하게하려면 입심이되지 char, gchar 사용하지만의이 무시하자)

지금, 나는이 매개 변수가 왜 궁금 char **str_array 및 아닙니다 const char **str_array. 그것은 컴파일러의 경고를 제거하는 명시 적 캐스트를 할 저를 강제로 (" '문자 **'하지만 인수는 '** const를 문자'유형 인 기대") :

puts(g_strjoinv("+", (char **)words)); 

나는 GLib's reference 및 I 보면 그 을 모두보십시오이 방법으로 정의 된 기능 : 그들이 char **, 아니 const char ** 받아들입니다.

왜 그럴까요? GLib에서 const char **을 사용하지 않는 이유는 무엇입니까?

const를 제거하기 위해 명시 적 형변환을 사용해야하는 이유는 컴파일러가 더 이상 인수의 호환성을 검사하지 않기 때문에 내 코드를 안전하지 않게 만듭니다. 또한 GLib은 내 데이터를 변경하지 않는다고 말하는 "계약서에 서명하지"않기 때문에 걱정이됩니다.

+1

위대한 질문으로, str_array는 확실히 변경되지 않습니다 (?).이 경우 const가 적합합니다. – this

+0

@self : 그래,이 기능만으로는 문제가되지 않습니다. GLib 함수의 * all *에 문자열 배열을 허용합니다. 나는 그들이 이것을하기에 좋은 이유가 있다고 생각하고 그것이 무엇인지를 알고 싶다. –

+3

[이 질문] (http://c-faq.com/ansi/constmismatch.html)을 참조하십시오. 전적으로 가능하다면'const char **'를 기대할 수있는 함수에 전달할 수 없기 때문에 문제가 해결되지 않을 것입니다. 그것을 그대로 선언한다. –

답변

6

귀하의 질문에 가정이 g_strjoinv()의 두 번째 인수 유형 const char **로 선언 된 경우, 당신은 그냥 간단하게 전달할 수 있다는 것입니다 중 하나 const char ** 나에 char **.

불행히도 이것은 사실이 아닙니다. this question from the comp.lang.c FAQ에서 설명했듯이 T (모든 유형의 경우 T)에 대한 포인터를 사용하면 const T에 대한 포인터가 필요하지만 불일치가 가장 낮은 수준의 간접 참조 인 경우에만 사용할 수 있습니다. 즉, const char *이 예상되는 곳에 char *을 전달할 수 있지만 캐스트가없는 경우 을 전달할 수 없습니다. 여기서는 const char **이 예상됩니다.이 경우 불일치가 두 번째 간접 레벨에 있기 때문입니다. 링크 된 질문은 인 이유가 무엇인지를으로 설명합니다.이 방식은 "다소 모호합니다".

결과적으로 캐스팅을 필요로하는 적어도 하나가 없으면 char **const char **을 모두 허용하는 유형이 없습니다 (C에서). 그렇기 때문에 편의성 이외의 다른 것을 선호하는 이유는별로 없을 것입니다. 그리고 도서관 저자들은 분명히 이전과 함께 가기로 결정했습니다. 순수한 추측의 문제로, char **을 전달하려는 것은 const char **을 전달하려는 것보다 약간 더 일반적이며, 따라서 그들이 선택한 옵션은 아마도 더 편리 할 것입니다.

귀하의 경우 배열 정의에서 const 한정자를 삭제할 수 있습니다.만약 당신이 const을 좋아한다면 나쁜 형식처럼 보일지 모르지만, 문자열 리터럴을 가리키는 포인터 배열을 가지고 있기 때문에 어쨌든 어떤 프로그램이든 쓰기를 시도하면 프로그램이 크게 불평하고 실패 할 확률이 높습니다. 이 특별한 경우에 의미있는 방식으로 안전을 잃어 버리게됩니다. 문자열 리터럴은 정의되지 않은 동작이지만 C에서와 달리 배열이 아닌 char의 형식 배열을가집니다 (C++과 달리).

좀 더 명확하지 않지만, const char **으로 전달할 수 있다고해도, 여기에있는 함수는 포인터가 가리키는 것을 수정할 수없고 다른 방법으로 신체 상해를 일으킬 수 있다고해도 포인터를 수정할 수 있습니다. 만든 함수가 여전히 함수에 전달하는 것이 어떤 식 으로든 변경되지 않는다는 것을 보장하지 않을 것이라고 약속하십시오.

+0

** 우수 ** 답변입니다, 정말 고마워요! 이전에이 문제가 발생 했었지만이 사례와 관련이 있는지 몰랐습니다. 자, 덕분에, 나는 그것을 완전히 이해합니다. BTW, 당신은 내가 "const"를 그냥 떨어 뜨릴 수 있다고 말하지만 GCC가 나를 경고 할 때 ("initialization discards 'const'..."), 문자열 상수를 상수로 간주하기 때문에 경고한다. –

+0

(BTW, 마지막 단락도 감사드립니다. 내 C 기술은 약간 녹슬었고이 수정이 필요했습니다.) –

+0

위의 경고처럼 들리 겠지만 C++ 또는 일부 확장 집합으로 컴파일하지 않았습니까? ? 표준 C로 컴파일하면 경고를해서는 안됩니다. –

관련 문제