2011-09-09 5 views
3

PHP 용 C 확장을 작성 중이며 일부 하위 문자열을 기반으로 문자열을 작성해야합니다. 현재는 다음과 같습니다 :문자열 연결 - 깨끗한 방법으로 어떻게이 작업을 수행합니까?

spprintf(
    &bucket_list_url, 
    strlen(host) + 1 + sizeof(port) + 1 + strlen(prefix) +strlen("?buckets=true"), 
    "%s:%d/%s?buckets=true", 
    host, 
    port, 
    prefix 
); 

작동하지만 끔찍하고 유지하기 어려울 수 있습니다. 이 문자열들을 안전하게 연결하기위한 더 깨끗한 방법이 있습니까?

저는 C에서 초보자입니다. 아마도 눈치 챘을 것입니다. 그래서 지금까지는 더 깨끗한 해결책을 찾지 못했습니다.

답변

3

GNU C 런타임 (glibc)을 사용하는 경우 asprintf(3) 함수를 사용하여 문자열을 동적으로 할당 된 버퍼로 포맷 할 수 있습니다. 그렇게하면 버퍼가 충분히 크다는 것에 대해 걱정할 필요가 없습니다. 예를 들면 : 당신의 glibc를 사용하지 않는 경우

// Error checking omitted for expository purposes 
char *bucket_list_url; 
asprintf(&bucket_list_url, "%s:%d/%s?buckets=true", host, port, prefix); 
... // do stuff 
free(bucket_list_url); 

, 당신은 여전히 ​​snprintf(3)를 사용할 수 있지만 버퍼 길이 추측해야합니다. 잘못 추측 한 경우 더 큰 버퍼를 할당하고 다시 시도해야합니다.

+0

흠을 훨씬 더 보이는, 그것을 시도를 제공합니다 감사 – Max

+0

는 한 번 추측 할 수 snprintf' 하지만 실패하면 다시 필요한 공간을 알려주기 때문에 "다시 시도하지 마십시오. (물론, 처음에'snprintf (NULL, 0, ...) '을 사용하여 추측 할 수 있지만 주어진 상황에 대해 당신이 필요로하는 것을 교육적으로 추측하여주기를 절약 할 수 있습니다.) –

0

은 당신이 현재 snprintf 사용하는 것이 의미 있다고 생각 : 현재 snprintf의 두 번째 매개 변수는 바이트의 첫 번째 매개 변수의 길이

char bucket_list_url[1024]; 

snprintf(bucket_list_url, sizeof(bucket_list_url), "%s:%d/%s?buckets=true", host, port, prefix); 

을, 당신은 함수 호출 후 얻을 것으로 예상되는 문자열의 길이가 아닙니다 .

0

내가 잠시 뒤로 쓴 작은 발췌 문장입니다. 아마 어리석은 짓일 수도 있지만, 아마도 당신이 찾고있는 것이 겠지요. 참고 : 두 개의 vsnprintf이 있기 때문에 가장 효율적이지 않습니다. 첫 번째는 버퍼의 길이를 결정하는 것입니다. `으로

 

char * new_string_from_format(const char * fmt, ...) { 
    int size; 
    char * string_buffer; 

    assert(fmt != NULL); 
    assert(strlen(fmt) > 0); 

    // first determine the length the buffer should be 
    va_list args; 
    va_start(args, fmt); 
    size = vsnprintf(NULL, 0, fmt, args) + 1; 
    va_end(args); 
    assert(size > 0); 


    string_buffer = new char[size]; 
    va_start(args, fmt); 
    vsnprintf(string_buffer, size, fmt, args); 
    va_end(args); 

    return string_buffer; 
} 

 

그것의 glibc의 asprintf 아마 비슷한 (하지만 glibc는 필요하지 않습니다.)

+1

질문은 C++가 아닌 C로 태그가 붙어 있습니다. 조금이라도 청소하고 싶을 수도 있습니다. (그리고 C (또는 C++) 컴파일러가 몇 가지 C99 기능을 지원한다면'v' 버전의 이것을 만들고'va_end' /'va_start' 대신'va_copy'를 사용하십시오) (그리고 더 효율적으로 사용하지 않겠습니까? 'std :: string :: reserve'를 사용하고 자신의 버퍼를 버리는 대신에'std :: string'의 버퍼를 사용하십시오.) –

+0

좋은 지적; 나는 C++을 꺼냈다. 그리고 다른 제안에도 감사드립니다. 나는 그것들을 내 자신의 코드에 추가하는 것을 고려할 것이고, 모두 잘된다면 이것을 업데이트 할 것이다. – Tom

관련 문제