2016-11-28 6 views
6

나는 C 동적 배열 라이브러리를 만들고있다. 참고 : 나는 자유 시간에을 재미있게 만들고 있기 때문에 기존의 수많은 도서관을 권장하지 마십시오.qsort와 함께 memcmp를 사용할 수 있습니까?

필자는 정렬 작업을 시작했습니다. I 원래 정렬 기능을 시작하기 위해 준비

typedef struct { 
    //[PRIVATE] Pointer to array data 
    void *array; 
    //[READONLY] How many elements are in array 
    size_t length; 
    //[PRIVATE] How many elements can further fit in array (allocated memory) 
    size_t size; 
    //[PRIVATE] Bytes per element 
    size_t elm_size; 
} Array; 

: 배열 구조체로 정의 된 임의의 요소의 크기이다 I 배운 그러나

/** sorts the array using provided comparator method 
* if metod not provided, memcmp is used 
* Comparator signature 
* int my_comparator (const void * ptr1, const void * ptr2, size_t type_size); 
**/ 
void array_sort(Array* a, int(*comparator)(const void*, const void*, size_t)) { 
    if(comparator == NULL) 
     comparator = &memcmp; 
    // Sorting algorithm should follow 
} 

qsort :

void qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const void*)); 

분명히 내 내부 배열을 qsort으로 전달할 수 있습니다.

qsort (a->array, a->length, a->elm_size, comparator_callback); 

을하지만 함정이있다 - qsort의 비교기 서명으로 읽습니다 : memcmp

int (*compar)(const void*,const void*) 

동안 '나는 그냥 부를 수의 서명은 다음과 같습니다

int memcmp (const void * ptr1, const void * ptr2, size_t type_size); 

요소 크기 qsort의 콜백에 누락되었습니다. 즉, NULL이 콜백으로 전달되면 더 이상 일반 비교 함수를 사용할 수 없습니다. 필자는 수동으로 요소 크기의 X 바이트까지 비교기를 생성 할 수 있지만 추한 것처럼 들립니다.

(또는 다른 분류 내장형)을 memcpy과 함께 사용할 수 있습니까? 아니면 내장형 비교기와 내장 정렬 기능 중 하나를 선택해야합니까?

+0

"기존 라이브러리를 100 만 건으로 권장하지 마십시오. *"웃었다. –

+0

비교 함수에 전달 된 포인터는 Array 포인터가 될 것입니다. Array로 캐스팅 한 다음 해당 구조체의 length 멤버를 사용하여 비교할 바이트 수를 결정할 수 있습니다. – JJF

+0

'qsort'의 요소 크기가 배열의'elm_size'가 아닌가요? – usr2564301

답변

1

스레드 안전하지 않은 방법은 크기를 전달하기 위해 개인 전역 변수를 사용하는 것입니다.

static size_t compareSize = 0; 

int defaultComparator(const void *p1, const void *p2) { 
    return memcmp(p1, p2, compareSize); 
} 

void array_sort(Array* a, int(*comparator)(const void*, const void*, size_t)) { 
    if(comparator == NULL) { 
     compareSize = a->elm_size; 
     comparator = &defaultComparator; 
    } 
    // Sorting algorithm should follow 
} 

당신은 스레드 안전 compareSize 스레드 로컬 변수 (__thread)

+0

나는 이것을 생각했지만, 멀티 스레딩과 함께 사용하지 않을 것이라고 생각합니다. 그것이 유일한 옵션이라면, 나는 붙여 넣기를 복사하고 GNU C 라이브러리에서'qsort '를 편집 할 것입니다. –

+0

왜? C의 전역 변수는 때로는 불가피합니다. 내부 연결로함으로써 어떤 문제도 발생하지 않습니다. –

+0

저는 C에 익숙하지 않았습니다. 나는 그것을 몰랐습니다. '__thread'를 사용하는 방법에 대한 세부 사항을 추가 할 수 있습니까? 휴대용입니까? –

4

C11이 특정 상황에 대처하도록하는 (틀림 옵션) qsort_s function, 당신을 제공하기로 만들 수 있습니다. 호출 코드에서 비교 함수로 사용자가 제공 한 void * 값 (컨텍스트 포인터)을 통과시킬 수 있습니다. 이 경우 비교기 콜백은 상황

#define __STDC_WANT_LIB_EXT1__ 1 
#include <stdlib.h> 
... 

int comparator_callback(const void *x, const void *y, void *context) 
{ 
    size_t elm_size = *(const size_t *) context; 
    return memcmp(x, y, elm_size); 
} 

... 
qsort_s(a->array, a->length, a->elm_size, comparator_callback, &a->elm_size); 

로 크기 값에 대한 포인터를 전달할 수 있습니다하거나 포인터를 전달하는 데 적합 할 수 있습니다 간단한 경우에는 다음과 같은 서명

int (*compar)(const void *x, const void *y, void *context) 

을 가지고 당신의 전체 배열 객체를 컨텍스트로 표시합니다.

일부 * nix 기반 구현은 비표준 임에도 불구하고 잠시 동안 비슷한 qsort_r function을 제공합니다.

+0

저는 C99을 필요로하는 숙제에 라이브러리를 사용하고 있습니다 만, 일반적으로 유용하기 때문에 나는 여전히 이것을 upvoted했습니다. –

1

qsort() API는 단순한 시대의 유산입니다. 각 비교에 대한 qsort() 호출에서 변경되지 않고 전달되는 추가 "환경"포인터가 있어야합니다.이렇게하면 객체 크기와 기타 필요한 컨텍스트를 스레드에 안전하게 전달할 수 있습니다.

하지만 여기에는 없습니다. @ BryanChen의 방법 만이 유일한 합리적인 방법입니다.

나는이 대답을 쓰고 있어요 주된 이유는 memcmp 유용한 일을 할 것입니다 매우 몇 가지 경우가 있음을 지적하는 것입니다. 구성 요소의 사전 식 순서에 의한 비교가 의미가있는 많은 종류의 객체가 없습니다. 패딩 바이트 값이 지정되지 않은 때문에

은 물론 struct의 그런 식으로 비교하는 것은 위험하다. 비교의 평등 부분조차도 실패 할 수 있습니다. 즉,

struct foo { int i; }; 

void bar(void) { 
    struct foo a, b; 
    a.i = b.i = 0; 
    if (memcmp(&a, &b, sizeof a) == 0) printf("equal!"); 
} 

- C 표준 - 인쇄물 없음!

또 다른 예 : unsigned int의 같은 간단한 들어, BIG-대 리틀 엔디안 저장하기 위해 다른 정렬 순서를 얻을 수 있습니다.

unsigned a = 0x0102; 
unsigned b = 0x0201; 
printf("%s", memcmp(&a, &b, sizeof a) < 0 ? "Less! : "More!"); 

은 실행중인 시스템에 따라 Less 또는 More을 인쇄합니다.

는 사실 내가 그 memcmp와 비교하는 의미가 상상할 수있는 유일한 오브젝트 유형은 부호없는 바이트의 동일한 크기의 블록이다. 이것은 정렬을위한 매우 일반적인 사용 사례는 아닙니다. 모두

, 비교 기능이 오류가 발생하기 쉬운 될 운명으로 memcmp을 제공하는 라이브러리입니다. 누군가는 원하는 결과를 얻는 유일한 방법 인 특수 비교를 대신하여이를 사용하려고 시도합니다.

+0

특정 순서가 플랫폼에 따라 다르다는 것은 사실이지만 OP의 상황에서 특정 순서가 중요하다는 것을 의미하지는 않습니다. 아마도 OP는 요소의 상대적 위치가 아닌 동등한 요소의 그룹화에만 관심을 가질 수 있습니다. 기본적으로 C++의 std :: unordered_set 안에있는 요소 순서는 하나의 플랫폼/구현과 다를 수 있습니다. stuill은 std :: unordered_set의 사용 목적을 의도 된 용도로 제한하지 않습니다. – AnT

+0

@AnT 그는 동적 배열 라이브러리를 구축 중입니다. 나는 그것이 포함하고있는 타입이 임의적이라고 가정하는 것이 합리적이라고 생각합니다. 바이트 단위의 임의의 형태를 사전 식으로 비교하는 것은 거의 불가능합니다. – Gene