2010-03-16 4 views
10

void 포인터 (일반 포인터)를 사용하여 C에서 범용 코드를 작성할 수는 있지만, void 포인터는 경고없이 모든 포인터 유형을 취할 수 있기 때문에 코드를 디버그하는 것은 매우 어렵습니다. 컴파일러에서. (예 : foo() 함수는 struct에 대한 포인터가 될 void 포인터를 취합니다. char 배열이 전달되면 컴파일러는 불평하지 않습니다.) C에서 void 포인터를 사용할 때 어떤 접근 방식이나 전략을 사용합니까?void 포인터가있는 C의 일반적인 프로그래밍

comp.lang.c FAQ list · Question 4.9

Q는 : 내가 인수로 일반적인 포인터를받는 함수를 작성한다고 가정하고 나는 참조하여 전달 시뮬레이션 할

+4

이 경우를 C의 유일한 질문입니다 C++ 태그를 제거하십시오 –

+13

흠 ... "나는 망치로 손가락을 때리면 커다란 시간을 아프게합니다. 망치로 신체 부위를 때릴 때 어떤 접근 방식을 사용합니까?" – sharptooth

+2

void *를 사용하는 C 제네릭 프로그래밍이 우아하고 사용하기에 좋다고 생각한다면 qsort 함수를 사용하기 위해해야 ​​할 일을 살펴보십시오 ... –

답변

8

당신이 정말로해야하지 않는 한 해결책은 void*을 사용하지 않아야합니다. void 포인터가 실제로 필요한 장소는 함수를 쓰는 데 필요한 매개 변수와 일반적인 함수를 통해 구현 관련 데이터를 전달해야하는 소수의 장소입니다. 모든 경우에 void* 매개 변수를 사용하는 코드는 void 포인터를 통해 데이터 형식 만 전달해야하며 형식은 주석으로 문서화되고 모든 호출자가 철저히 준수해야합니다.

+4

OP는 구체적으로 공백 * (템플릿이나 멋진 매크로 같은 더 높은 수준의 언어 기능이없는 경우)에 대한 유용한 유스 케이스 인 일반적인 프로그래밍을 언급했습니다. –

+0

예를 들어, , qsort() 및 bsearch() –

+0

@Matt, qsort 및 bsearch는 "일반 함수를 통한 구현 관련 데이터"의 예입니다. –

4

이 도움이 될 수 있습니다. 공식 매개 변수 유형 void **를 부여 할 수 있습니까?

void f(void **); 
double *dp; 
f((void **)&dp); 

A : 휴대 할 수 없습니다. 이와 같은 코드가 작동하고 때로는 권장되는 경우도 있지만, 내부 표현이 같은 모든 포인터 유형 (일반적이지만 일반적인 것은 아닙니다. 질문 5.17 참조)에 의존합니다.

void *는 void (*)에 다른 포인터 유형이 할당 될 때 자동으로 적용되기 때문에 일반 포인터로 사용됩니다. void * 이외의 포인터 유형을 가리키는 void ** 값에 간접적 인 시도가있을 경우 이러한 변환을 수행 할 수 없습니다. void ** 포인터 값을 사용할 때 (예를 들어 * 연산자를 사용하여 void **가 가리키는 void * 값에 액세스 할 때) 컴파일러는 void * 값이 한 번인지 여부를 알 수 없습니다 다른 포인터 유형에서 변환됩니다. 그것은 무언가 이상이라고 가정해야합니다 *; 암시 적 변환을 수행 할 수 없습니다.

즉, 사용자가 재생할 void ** 값은 어딘가에 실제 void * 값의 주소 여야합니다. (void **) & dp와 같은 캐스트는 컴파일러를 닫을 수도 있지만, 이식성이 없다. (그리고 원하는 것을하지 않을 수도있다; 질문 [*] 13.9를 참고). void **가 가리키는 포인터가 void *가 아니고 void *와 다른 크기 나 표현을 가진다면 컴파일러는 올바르게 접근하지 못할 것입니다.

가 주어진 코드를 동작하게 만들려면, 당신은 void * 타입 변수 : 컴파일러에게 필요한 경우, 어떤 변환을 수행 할 수있는 기회를 제공 및 부사장에서

double *dp; 
void *vp = dp; 
f(&vp); 
dp = vp; 

과제물.

또 다른 포인터 유형은 크기 나 표현이 다를 수 있으며, 희귀하지만 전례가없는 것으로 가정합니다. void **의 문제를보다 명확하게 이해하려면 상황을 int 및 double 유형과 관련된 유사 유형과 비교하십시오. 아마도 크기가 다르며 확실히 다른 표현을 가질 것입니다. 우리는 함수를

void incme(double *p) 
{ 
    *p += 1; 
} 

이있는 경우 다음이 ** 코드 보조 부사장을 포함하는 올바른 무효 유사하다 (우리는

int i = 1; 
double d = i; 
incme(&d); 
i = d; 

처럼 뭔가를 할 수와 나는 1 씩 증가됩니다.반면에, 우리는 (이 코드는 질문에 나온)

int i = 1; 
incme((double *)&i); /* WRONG */ 

같은 것을 시도했다, 경우), 작동 할 가능성은 희박하다.

-2

우리 모두는 C 타입 시스템이 기본적으로 쓰레기지만, 그렇게하려고하지는 않는다는 것을 알고 있습니다 ... 당신은 여전히 ​​일반 타입을 처리 할 수있는 몇 가지 옵션을 가지고 있습니다 : 공용체와 불투명 포인터.

어쨌든 제네릭 함수가 void 포인터를 매개 변수로 사용하는 경우이를 역 참조하지 말아야합니다.

1

접근/전략은 void * 포인터의 사용을 최소화하는 것입니다. 그들은 특정한 경우에 필요합니다. void *를 실제로 전달해야하는 경우 포인터의 타겟 크기도 전달해야합니다.

0

이 일반적인 스왑 기능은 일반적인 무효 * 이해에 많은 도움이됩니다

#include<stdio.h> 
void swap(void *vp1,void *vp2,int size) 
{ 
     char buf[100]; 
     memcpy(buf,vp1,size); 
     memcpy(vp1,vp2,size); 
     memcpy(vp2,buf,size); //memcpy ->inbuilt function in std-c 
} 

int main() 
{ 
     int a=2,b=3; 
     float d=5,e=7; 
     swap(&a,&b,sizeof(int)); 
     swap(&d,&e,sizeof(float)); 
     printf("%d %d %.0f %.0f\n",a,b,d,e); 
return 0; 
} 
아리아의 솔루션은 가변 크기 지원하기 위해 약간 변경 될 수 있습니다
+2

크기가 100보다 큰 경우 어떻게됩니까? –

2

:

#include <stdio.h> 
#include <string.h> 

void swap(void *vp1,void *vp2,int size) 
{ 
    char buf[size]; 
    memcpy(buf,vp1,size); 
    memcpy(vp1,vp2,size); 
    memcpy(vp2,buf,size); //memcpy ->inbuilt function in std-c 
} 

int main() 
{ 
    int array1[] = {1, 2, 3}; 
    int array2[] = {10, 20, 30}; 
    swap(array1, array2, 3 * sizeof(int)); 

    int i; 
    printf("array1: "); 
    for (i = 0; i < 3; i++) 
    printf(" %d", array1[i]); 
    printf("\n"); 

    printf("array2: "); 
    for (i = 0; i < 3; i++) 
    printf(" %d", array2[i]); 
    printf("\n"); 

    return 0; 
} 
관련 문제