문자열을 반환하는 함수, 좋은 스타일?


11

내 C 프로그램에서 종종 ADT의 문자열 표현을 만드는 방법이 필요합니다. 어떤 식 으로든 문자열을 화면에 인쇄 할 필요가 없더라도 디버깅을위한 그러한 방법이 있어야합니다. 이런 종류의 기능이 종종 등장합니다.

char * mytype_to_string( const mytype_t *t );

실제로 문자열을 반환하기 위해 메모리를 처리하기위한 적어도 세 가지 옵션이 있음을 알고 있습니다.

대안 1 : 함수의 정적 문자 배열에 반환 문자열 저장 매번 호출 할 때마다 문자열을 덮어 쓰는 것을 제외하고는 많은 생각이 필요하지 않습니다. 어떤 경우에는 문제가 될 수 있습니다.

대안 2 : 함수 내부에 malloc을 사용하여 힙의 문자열을 할당하십시오. 버퍼 크기 또는 덮어 쓰기를 생각할 필요가 없으므로 정말 깔끔합니다. 그러나 완료되면 문자열을 free ()해야한다는 것을 기억해야하며 여유 변수가 될 수 있도록 임시 변수를 할당해야합니다. 힙 할당은 스택 할당보다 훨씬 느리므로 루프에서 반복되면 병목 현상이 발생합니다.

대안 3 : 버퍼에 대한 포인터를 전달하고 호출자가 해당 버퍼를 할당하도록합니다. 처럼:

char * mytype_to_string( const mytype_t *mt, char *buf, size_t buflen ); 

이것은 발신자에게 더 많은 노력을 기울입니다. 또한이 대안이 나에게 인수 순서에 대한 다른 옵션을 제공한다는 것을 알았습니다. 첫 번째와 마지막으로해야 할 주장은 무엇입니까? (실제로 6 가지 가능성)

그렇다면 어느 것을 선호해야합니까? 왜요? C 개발자들 사이에 어떤 종류의 기록되지 않은 표준이 있습니까?


3
참고로, 대부분의 운영 체제는 옵션 3을 사용합니다. 발신자는 버퍼를 할당합니다. 버퍼 포인터와 용량을 알려줍니다. 수신자가 버퍼를 채우고 버퍼 가 부족한 경우 실제 문자열 길이를 반환합니다 . 예 : sysctlbynameOS X 및 iOS에서
rwong

답변:


11

가장 많이 본 방법은 2와 3입니다.

사용자 제공 버퍼는 실제로 사용하기가 매우 간단합니다.

char[128] buffer;
mytype_to_string(mt, buffer, 128);

대부분의 구현에서는 사용 된 버퍼의 양을 반환합니다.

옵션 2는 다른 런타임 (및 다른 힙)을 사용할 수있는 동적 링크 라이브러리를 사용할 때 속도가 느리고 위험합니다. 따라서 다른 라이브러리에서 malloced 된 것을 해제 할 수 없습니다. 그런 다음이 free_string(char*)를 처리 하는 기능 이 필요 합니다.


감사! 대안 3을 가장 좋아한다고 생각합니다. 그러나 나는 다음 printf("MyType: %s\n", mytype_to_string( mt, buf, sizeof(buf));과 같은 일을 할 수 있기를 원합니다. 따라서 사용 된 길이를 반환하지 않고 문자열에 대한 포인터를 반환하고 싶습니다. 동적 라이브러리 주석이 정말 중요합니다.
Øystein Schønning-Johansen

이것이 터미네이터 sizeof(buffer) - 1를 만족시키지 않아야 \0합니까?
Michael-O

1
@ Michael-O 널 크기가 버퍼 크기에 포함되지 않음은 넣을 수있는 최대 문자열이 전달 된 크기보다 1이 작음을 의미합니다. 표준 라이브러리에서 안전한 문자열이 snprintf사용하는 것과 같은 패턴입니다 .
ratchet freak

@ratchetfreak 설명해 주셔서 감사합니다. 그 지혜로 대답을 확장하는 것이 좋을 것입니다.
Michael-O

0

# 3을위한 추가 디자인 아이디어

가능 mytype하면 같은 .h 파일에 필요한 최대 크기도 제공하십시오 mytype_to_string().

#define MYTYPE_TO_STRING_SIZE 256

이제 사용자는 그에 따라 코딩 할 수 있습니다.

char buf[MYTYPE_TO_STRING_SIZE];
puts(mytype_to_string(mt, buf, sizeof buf));

주문

배열 크기는 처음에 VLA 유형을 허용합니다.

char * mytype_to_string( const mytype_t *mt, size_t bufsize, char *buf[bufsize]); 

단일 차원에서는 그다지 중요하지 않지만 2 이상에서는 유용합니다.

void matrix(size_t row, size_t col, double matrix[row][col]);

다음 C에서는 먼저 크기를 갖는 것이 좋은 관용구라는 것을 기억합니다. 그 참조를 찾아야합니다 ....


0

@ratchetfreak의 탁월한 대답에 덧붙여 대안 # 3은 표준 C 라이브러리 함수와 유사한 패러다임 / 패턴을 따릅니다.

예를 들면 다음과 같습니다 strncpy.

char * strncpy ( char * destination, const char * source, size_t num );

동일한 패러다임을 따르는 것은 새로운 개발자 (또는 미래의 자기 자신)가 함수를 사용해야 할 때인지 부하를 줄이는 데 도움이됩니다.

게시물에있는 것과의 유일한 차이점 destination은 C 라이브러리의 인수가 인수 목록에서 첫 번째로 나열되는 경향이 있다는 것입니다. 그래서:

char * mytype_to_string( char *buf, const mytype_t *mt, size_t buflen ); 

-2

당신이 제안하는 것이 나쁜 코드 냄새라는 사실 외에도 대안 3이 가장 좋습니다. 또한 @ gnasher729와 같이 잘못된 언어를 사용하고 있다고 생각합니다.


코드 냄새를 정확히 어떻게 생각하십니까? 정교하게 작성하십시오.
헐크

-3

솔직히 말하면 문자열 반환이 복잡하지 않고 작업 집약적이며 오류가 발생하기 쉬운 다른 언어로 전환하려고 할 수 있습니다.

코드의 99 %를 그대로 두는 C ++ 또는 Objective-C를 고려할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.