2014-04-05 2 views
1
  • 플랫폼 : 리눅스 3.2.0 86 (데비안 위지)
  • 컴파일러 : GCC 4.7.2 (데비안 4.7.2-5)

내가 쓰고 있어요 함수는 버퍼의 내용을 다른 버퍼에 복사합니다. 함수가 특정 유형이 아닐 수 있도록 void 포인터를 사용합니다. 테스트 할 수있는 버전이 있는데이 함수가 제대로 작동하고있는 것으로 보입니다. 그러나 내가하고있는 일이 합법적인지 여부는 알 수 없으므로 내 질문은 내가 무엇을했는지에 대한 함정입니다.Deferencing 무효 포인터/무효 포인터 복사

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

void* voidcpy(void *void_ptr, size_t nbytes) 
{ 
    char *char_ptr = void_ptr; 
    char *cpy_char_ptr = NULL; 
    size_t i = 0; 

    if((cpy_char_ptr = malloc(nbytes)) == NULL) return NULL; 

    for(; i < nbytes; i++) cpy_char_ptr[i] = char_ptr[i]; 

    return cpy_char_ptr; 
} 

int main() 
{  
    short int *intp = NULL; 
    short int *cpy_intp = NULL; 
    size_t siz = 5; 
    int i = 0; 

    if((intp = malloc(siz * sizeof(short int))) == NULL) 
    { 
     perror("(malloc)"); 
     return -1; 
    } 

    intp[0] = 0; 
    intp[1] = 14; 
    intp[2] = 187; 
    intp[3] = 12678; 
    intp[4] = -234; 

    if((cpy_intp = voidcpy(intp, siz * sizeof(short int))) == NULL) 
     return -2; 

    printf("intp = %p\ncpy_intp = %p\n\n", (void*)intp, (void*)cpy_intp); 

    for(; i < siz; i++) printf("cpy_intp = %i\n", cpy_intp[i]); 

    free(intp); 
    free(cpy_intp); 

    return 0; 
} 
+2

'memcpy'를 사용하십시오. BLUEPIXY

+1

@BLUEPIXY memcpy()에 대해 알고 있습니다. 솔루션으로 안내해 주셔서 감사하지만 일반적으로 void 포인터와 데이터 형식을 더 잘 이해하기 위해이 작업을 수행하고 있습니다. –

+1

특히 문제가 있다고 생각하지 않습니다. – BLUEPIXY

답변

1

예,이 C에서 당신은 법적으로 다른 포인터 타입에 무효 포인터를 할당 할 수 있습니다 당신은 무효 포인터에 어떤 포인터 타입을 할당 할 수 있습니다, 완벽하게 합법적이다.

C++에서는 허용되지 않습니다. C++에서는 C에서 허용되는 무효 포인터 캐스팅이 실수를하기 쉬운 "루프 구멍"으로 간주되기 때문에 reinterpret_cast을 다른 포인터 유형으로 캐스팅해야합니다.

물론 그 아이디어에는 진실이 있습니다.주의를 기울이지 않으면 잘못된 것을 할 수 있습니다. 당신은 실수로이 함수 포인터를 가리키는 포인터를 쉽게 넘길 수 있습니다. 그런 다음 함수는 그 포인터를 넘어서는 스택에있는 모든 것을 행복하게 덮어 씁니다. 이것은 구현의 잘못이 아니지만, 함수가 사용되는 방식 일 뿐이며 memcpy는 별다른 동작을하지 않습니다.

그럼에도 불구하고 memcpy을 사용하는 것이 더 나을 것입니다. 요즘 컴파일러가 코드의 꽤 괜찮은 버전을 만들지 만 훨씬 더 최적화 될 가능성이 높기 때문입니다.

몇 가지 더 많은 포인터가 있습니다.

1) 당신은 다음과 같은 방법으로 함수를 호출 할 수 있습니다) 그렇게

short int int_arr[] = { 
    0, 
    14, 
    187, 
    12678, 
    -234, 
}; 

이 같은 정적으로 초기화 할 수 있습니다, 원래의 배열을 malloc을 할 필요가 없습니다 :

cpy_int_arr = voidcpy(int_arr, sizeof(int_arr)); 

3) 배열을 정적으로 정의하고 싶지 않은 경우 포인터를 사용하여 요소 크기를 얻습니다. 이렇게하면 코드의 다른 위치에서 배열 유형을 변경할 필요없이 배열 유형을 변경할 수 있으므로 해당 요소의 잠재적 위험을 줄일 수 있습니다. "루프 홀"보이드 주조 :

cpy_intp = voidcpy(intp, siz * sizeof(*intp)); 

4) 당신이 printf 호출 void*로 캐스팅 할 필요가 없습니다

5) 즉시 변수를 할당하려고하면 문장의 내부 할당을 넣지 마십시오 :

char *cpy_char_ptr = malloc(nbytes) 
if (cpy_char_ptr == NULL) 
    return NULL; 

(6)) 마찬가지로 루프 절 내에 반복 변수를 정의 할 수 있습니다.

for(size_t i = 0; i < nbytes; i++) cpy_char_ptr[i] = char_ptr[i]; 

변수를 가능한 한 늦게 정의하고 즉시 초기화하려면 변수의 범위를 가능한 작게 유지해야하며 초기화되기 전에 실수로 변수를 사용할 수는 없습니다.

7) (개인 취향) 식별자에 형식 이름 (intp, voidcpy)을 사용하지 마십시오. 식별자가 변수의 실제 유형과 다른 유형을 나타내면 코드를 읽기/이해하기가 어려워집니다. 유형이 실제로는 short int이고 변수 이름이 int이 아닌 경우) 실수를 할 가능성이있는 유형을 변경할 때마다 전체 코드에서 식별자를 변경해야합니다.