2013-08-31 2 views
7

void **을 통해 포인터 유형에 액세스 할 수 있습니까?void를 통해 데이터 포인터를 수정하는 것이 맞습니까? **

내가 기준을 통해 검토 한 결과는 포인터 앨리어싱에 인용하지만, 난 여전히이 법적 C 여부에 확실 해요 :

int *array; 
void **vp = (void**)&array; 
*vp = malloc(sizeof(int)*10); 

사소한 예,하지만 내가 '더 복잡한 상황에 적용 보고 있습니다.

int * 또는 char *이 아닌 변수를 통해 int *에 액세스하고있어 합법적이지 않은 것으로 보입니다. 나는 이것에 관해서 간단한 결론에 도달 할 수 없다.

관련 : 다른 유형의

+0

는 "유형하지만"에 액세스하는'INT * '하는 것이 무슨 뜻 이죠? – ash

+0

Eli Bendersky는이 주제에 관한 블로그 글을 가지고 있습니다 : http://eli.thegreenplace.net/2009/11/16/void-and-casts-in-c-and-c/ –

+0

@MortenJensen * 그리고 무효가 아닙니다 ** –

답변

2

포인터는 서로 다른 크기를 가질 수있다.

당신은 void *으로 모든 유형에 대한 포인터를 저장하고 당신은 다시 복구 할 수 있지만, 이것은 void * 다른 모든 포인터를 보유 할만큼 충분히 커야 단순히 것을 의미한다. 그것은 void * 대신입니다 사실입니다 같은 int *을 들고 변수를 치료

, 일반적으로 허용되지 않습니다.

참고도 (예를 들어 int *malloc의 결과에 캐스팅) 캐스팅을하는 것은 그것이 void *을 포함하는 것 같은 int *를 포함하는 메모리의 영역을 치료 완전히 다른 무언가이다. 첫 번째 경우에는 컴파일러에 필요한 경우 변환 정보가 전달되고 두 번째에는 컴파일러에 잘못된 정보를 제공합니다.

그러나 X86에서는 대개 같은 크기이므로 데이터에 대한 포인터 만 가지고 놀면 안전합니다 (기능에 대한 포인터는 다를 수 있음).

void * 또는 char *을 통해 수행 된 모든 쓰기 작업은 모든 개체를 변경하여 컴파일러에서 가능하면 앨리어싱을 고려해야합니다. 여기에 예제에서는 void ** (다른 것)을 통해 작성 중이며 컴파일러는 int *에 대한 잠재적으로 앨리어싱 효과를 무시할 수 있습니다.

+0

포인터 크기와 관련이 있는지 잘 모르겠습니다. AFAIK,'void *'는 malloc()에 대한 모든 호출에서 반환 된 주소를 유지할 수 있습니다. 'int *'에 malloc()의 반환 값을 저장할 수 있다면, 대신에'void ** '를 통해 그렇게하면 상관 없습니다. 나에게 그것은'int *'와'void * '가 같은 크기를 가진다는 보장과 같이 보인다. 그렇지 않으면'int * a = malloc (N);과 같은 간단한 것은 정의되지 않은 행동이다. –

+0

그건 나에게 새로운 얘기 야. 같은 프로그램에있는 두 개의 포인터가 언제 다른 크기를 가질 수 있었을 까? – ash

+0

@ash 함수 포인터는'void * '와는 다른 크기를 가질 수 있으며 malloc()의 반환 값은 함수 포인터에 저장할 수 없습니다. –

4

번호 void **은 특정 유형 (void-to-pointer에 대한 포인터)을 갖습니다. 나는. 포인터의 기본 유형은 "void-to-pointer"입니다.

포인터를 int로 저장하는 경우 like 포인터 값을 저장하지 않습니다. 캐스트가 필요하다는 것은 강한 지표로 이 정의되어 있지 않으며 표준에 따라 동작이 정의되어 있습니다 (그렇지 않은 경우). 그러나 흥미롭게도, 을 사용하여 보통 void*을 사용하며 정의 된 동작을 나타냅니다. 즉,

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

int main() 
{ 
    int *array; 
    void *vp = &array; 
    int **parray = vp; 
    *parray = malloc(sizeof(int)*10); 
} 

은 합법입니다.귀하의 원래 예제는 을 캐스팅을 제거하고 Apple llvm 4.2 (clang)를 사용할 수없는 경우 호환되지 않는 포인터 유형, 즉 질문의 주제와 정확하게 일치하지 않기 때문에 컴파일되지 않습니다. 특정 오류 :

"호환되지 않는 포인터 타입 형식의 표현 'INT **'으로 초기화 '무효 **'"

및 당연히 그렇게.

0

코드는 일부 플랫폼에서 작동하지만 휴대용이 아닙니다. 그 이유는 C가 포인터 타입에 대한 일반적인 포인터를 가지고 있지 않기 때문이다. void *의 경우, 표준은 명시 적으로 타입과 다른 타입 간의 변환을 허용하지만, void **의 경우는 그렇지 않습니다. 이것이 의미하는 바는 컴파일러가 *vp의 값이 void *이 아닌 다른 유형에서 변환되었는지 여부를 알 수있는 방법이 없으므로 명시 적으로 캐스팅 한 것을 제외한 모든 변환을 수행 할 수 없다는 것입니다.

void dont_do_this(struct a_t **a, struct b_t **b) 
{ 
    void **x = (void **) a; 
    *x = *b; 
} 

이 컴파일러는 그 선이 곳 곳에서 b_t에 대한 포인터를 넣어 노력에도 불구하고, *x = *b 라인 void *-b_t *에서 암시 적 캐스트에 대해 불평하지 않습니다

이 코드를 고려 a_t에 대한 포인터 만 넣어야합니다. 실수는 실제로 포인터를 "포인터를 어디에 둘 수있는 포인터"에 "포인터를 a_t에 놓을 수있는 포인터"로 변환하는 이전 행에 있습니다. 이것은 가능한 암시 적 캐스트가없는 이유입니다. 산술 유형에 대한 포인터가있는 유사한 예는 C FAQ을 참조하십시오.

캐스트하면 컴파일러 경고를 종료해도 모든 포인터 유형이 동일한 내부 표현/크기 (예 : void **int *) 일 수 있으므로 위험합니다. 모든 경우에 코드를 작동하게하려면 사용해야 void * 중간 :

int *array; 
void *varray = array; 
void **vp = &varray; 
*vp = malloc(sizeof(int) * 10); 
관련 문제