2009-06-14 3 views
13

strtol()strtod()는 효과적으로 문자열에서 constness를 버리는 것을 허용하고 강제하는 것으로 보입니다 :strtol, strtod가 안전하지 않습니까?

#include <stdlib.h> 
#include <stdio.h> 

int main() { 
    const char *foo = "Hello, world!"; 
    char *bar; 
    strtol(foo, &bar, 10); // or strtod(foo, &bar); 
    printf("%d\n", foo == bar); // prints "1"! they're equal 
    *bar = 'X'; // segmentation fault 
    return 0; 
} 

위와 같이, 나는 어떤 캐스트도 직접 수행하지 않았습니다. 그러나 strtol()은 기본적으로 내 const char *char *로 캐스팅합니다. 실제로 barconst char *로 입력 할 수 없기 때문에 안전하지 않은 유형의 변경이 필요합니다. 그렇게 위험하지 않습니까?

답변

13

나는 대안이 더 나빴 기 때문에 나는 그것을 추측 할 것이다. 프로토 타입은 const를 추가하도록 변경되었다 가정하자 :

char str[] = "12345xyz"; // non-const 
char *endptr; 
lont result = strtol(str, &endptr, 10); 
*endptr = '_'; 
printf("%s\n", str); // expected output: 12345_yz 

그러나 우리는이 코드를 컴파일 할 때 어떤 일이 발생 :

이제
long int strtol(const char *nptr, const char **endptr, int base); 

, 우리가 일정하지 않은 문자열을 구문 분석한다고 가정? 컴파일러 오류! 오히려 직관적이지는 않지만 char **을 암시 적으로 const char **으로 변환 할 수는 없습니다. 이유에 대한 자세한 설명은 C++ FAQ Lite을 참조하십시오. 그것은 기술적으로 C++에 대해 이야기하고 있지만 인수는 C에 대해서도 똑같이 적용됩니다. C/C++에서는 "유형에 대한 포인터"에서 "const유형에 대한 포인터"를 가장 높은 수준에서 암시 적으로 변환 할 수 있습니다 : 수행 할 수있는 변환은 char **에서 char * const *까지 또는 "(char)에 대한 포인터"에서 "const에 대한 포인터 char에 대한 포인터"와 같습니다.

정수가 아닌 문자열을 구문 분석하는 것이 상수 문자열을 구문 분석하는 것보다 훨씬 쉽다는 것을 알았 기 때문에 나는 그 가정을 계속합니다. const 보통의 경우 컴파일러 오류를 만드는 것이 바람직합니다.

+4

하지만 C++은 함수 오버로딩을 막지 않습니다. long int strtol (char * nptr, char ** endptr, int base);'* and *'long int strtol (const char * nptr, const char ** endptr, int base);': 이것은 컴파일 에러를 수정합니다. 사실, 표준은'strchr'과'strstr' 같은 다른 함수들에 대해서 이것을 수행합니다. – Thanatos

+0

C FAQ 웹 사이트 ['const char * p'와'char const * p'와 'char * const p'?] (http://c-faq.com/ansi/constptrconst.html), 특히''char ** '를''char **'를 기대하는 함수에 전달할 수없는 이유는 무엇입니까? const char **'?] (http://c-faq.com/ansi/constmismatch.html) 대신에 C++ FAQ를 사용하여 설명을 이해하기 쉽다고 전적으로 확신하지는 않습니다. –

1

첫 번째 인수의 'const char *'는 strtol()이 문자열을 수정하지 않는다는 것을 의미합니다.

반환 된 포인터로 수행 할 작업은 귀하의 비즈니스입니다.

예, 유형 안전 위반으로 간주 될 수 있습니다. C++은 아마 다르게 할 것입니다 (ISO/IEC 14882 : 1998은 C에서와 동일한 서명으로 <cstdlib>을 정의합니다).

+0

C++은 strtol (및 cstdlib의 다른 모든 것들)을 C와 동일한 서명으로 정의하지만 cstring 및 cwchar의 모든 것을 정의하지는 않습니다. –

6

예, 다른 함수에는 동일한 "const-laundering"문제가 있습니다 (예 : strchr, strstr, 모두 해당 사항).

정확하게 들어 이러한 이유로 C++는 오버로드를 추가한다 (21.4 : 4) : 함수 서명 strchr(const char*, int) 두 선언으로 대체됩니다 : 당신이 모두 const를-올바른 버전을 가질 수 없습니다 C에서 물론

const char* strchr(const char* s, int c); 
     char* strchr(  char* s, int c); 

그러나

같은 이름으로, const-incorrect 타협을 얻을 수 있습니다.

C++에는 strtol 및 strtod에 대한 유사한 오버로드가 언급되어 있지 않으며 실제로는 내 컴파일러 (GCC)에 포함되어 있지 않습니다.나는 왜 그런지 모르겠다. 당신이 암시 적으로 char**const char**에 오버로드하지 않음과 함께 설명 할 수 없다는 사실은 C에서 설명하지만, C++ 오버로드가 무엇이 잘못되었는지는 알 수 없다.

extern "C" { 
long int strtol(const char *nptr, const char **endptr, int base); 
long int strtol(char *nptr, char **endptr, int base); 
} 

은 분명히이 모두 동일한 링크 시간 심볼에 해결 :

long strtol(const char*, const char**, int); 
+1

stlport는이 오버로드 (및 다른 일부)를 제공합니다. –

1

나는 C++ 모드에서 컴파일 할 때, 제공하는 컴파일러를 가지고있다.

EDIT : C++ 표준에 따르면이 헤더는 컴파일되지 않아야합니다. 컴파일러가 단순히 이것을 확인하지 않았다고 생각합니다. 실제로 시스템 헤더 파일에 정의가 나타납니다.

관련 문제