2012-09-17 2 views
4
을 형식 정의 사용하여 포인터 타입에 대체 이름을 할당 혜택

가능한 중복 :
What is the right way to typedef a type and the same type's pointer?ANSI C -

나는 최근에 내 프로젝트에서 libxml2를 사용 해왔다과 같이 형식 정의를 사용하는 눈치 다음과 같습니다 :

typedef struct _xmlNode xmlNode 
typedef xmlNode * xmlNodePtr 

첫 번째 typedef의 이점은 분명합니다. 그러나 xmlNode *에 대체 이름을 지정하는 이유가 확실하지 않습니다. 나에게 더 명확하고 읽을 수있는 xmlNode *을 사용하는 것보다 xmlNodePtr하지만 뭔가가 누락되었을 수 있습니다.

이 typedef는 어떤 문제점을 해결할 수 있습니까? 또한 어떤 이점이 있습니까?

+1

그것은 취향의 문제이다. 나는 당신의 입장에 동의한다. (나는 포인터에 대해'typedef'-s처럼'xmlNodePtr'을 싫어한다.) 그리고 GTk는 그것을 사용하지 않습니다. (GCC 내부가 typedef'tree '를 가지고 있고 복잡한 데이터 타입을 가리키는 또 다른 typedef'gimple'이 있더라도). –

+2

이러한 종류의 typedef는 특별히 유용하지 않습니다. 그러나 포인터 typedef가 실제로 유용한 한 가지 경우는 함수 포인터를위한 것입니다. 왜냐하면 원시 함수 포인터 구문이보기에 지저분하기 때문입니다. – TJD

+1

FWIW, 여기에 리눅스 커널 개발자의 의견과 함께 몇 가지 근거가 있습니다 : http://www.kernel.org/doc/Documentation/CodingStyle –

답변

1

어떤 문제를 이 typedef는 해결할 것이고 어떤 이점을 가져다 줄 것입니까?

제 생각에는 객체 포인터를 typedefing하는 것은 좋지 않으므로 수행해서는 안됩니다.

먼저 선언 된 객체가 포인터 유형임을 숨김으로써 C 언어의 문법을 변경합니다.

두 번째 유형 한정자 (constvolatile)는 typedef를 투과 할 수 없습니다.

우리는 당신의 예를 취할 경우

typedef struct _xmlNode xmlNode; 
typedef xmlNode * xmlNodePtr; 

그것은 pointee가 xmlNodePtr 별칭을 사용 const 그래서 객체를 선언 이제 불가능하다.

const xmlNodePtr xp; 

xpconst하지 *xp 의미한다. 그들은 또한 포인터에 대한 typedef을 사용하지 않는 것이 좋습니다 리눅스 커널 코딩 스타일 그런데

const xmlNode x = /* ... */; 
const xmlNodePtr xp = &x; // Error! 

는 :

"그것은 구조와 포인터에 대한 형식 정의 사용하는 실수입니다."

+0

타입이 불투명 한 경우 값을 통해 데이터를 수정할 수 없으므로 클라이언트 코드에서'const'가 typedef를 관통하지 못하는 것이 중요하지 않습니다. 클래스 자체의 구현에있어 더 심각한 문제 일 수 있습니다. (나는 여전히 일반적으로 비 함수 포인터 타입의 typedef를 사용하지 않기를 바란다.) –

+0

커널 코딩 스타일을 취하면'typedef struct _xmlNode xmlNode;'는'typedef xmlNode * xmlNodePtr; '와 마찬가지로 나쁘다. 어쩌면 똑같이 나쁘지는 않지만 똑같이 금지 될 수도 있습니다. 이것은 아마도 포인터를 typedefing 할 생각을 가진 C 프로그래머를 놀라게하고 화나게 할 것이고, 커널 코딩 스타일의 조언을 완전히 없애 버릴 것이다. –

1

이름에 "ptr"이있는 typedef는 일반 포인터 구문을 사용하는 선언보다 읽기 쉽고 자연 스럽습니다. 당신이

foo* p; 

대신

foo *p; 

를 작성 좋아한다면 포인터는 특히 당신이

foo *p, *q; 
을 의미 할 때

foo* p, q; 

를 작성의 오류를 방지 당신에게 가능성 타입 정의 호소하기 때문에

대신 당신은

fooptr p, q; 
2

C API를 종종이 무엇인지 묻는 내부 찌를 시도에서 소비자를 낙담 불투명 핸들를 제공 쓸 수 있습니다. 이러한 핸들이 포인터라는 사실은 중요하지 않으며 소비자에게 중요하지 않아야하며 여분의 별의 어휘가 혼란스럽지도 않습니다.

typedef void * MyHandle; 

지금 우리는 행복한 C 소비자에게 일부 기능을 제공 :와

MyHandle create_gizmo(); 
void destroy_gizmo(MyHandle); 
int do_magic(MyHandle, int, int); 

간단한 예를 들어

, 그것은 핸들을 정의하여 바인딩 C++를 쓸 수 있도록 완벽하게 가능합니다. 사용자는 즉시 그것을 사용하는 방법을 본다 :

#include "MagicAPI.h" 

MyHandle h = create_gizmo(); 

submit_result(do_magic(h, 12, 91)); 

destroy_gizmo(h); 

그리고 C를 ++ 라이브러리 개발자는 단순히 핸들을 펼쳤다과 (extern "C"를 선언 물론되는) API 함수를 채 웁니다 :

#include "MagicAPI.h" 
#include "SuperGizmo.hpp" 

MyHandle create_gizmo() { return static_cast<MyHandle>(new SuperGizmo); } 

void destroy_gizmo(MyHandle h) { delete static_cast<SuperGizmo *>(h); } 

int do_magic(MyHandle h, int a, int b) 
{ 
    return static_cast<SuperGizmo *>(h)->foo(a, b); 
} 
+0

'typedef void * MyHandle'을 사용하면 함수의 오용으로 이어질 수 있습니다 'typedef struct MyStruct * MyHandle'은 그렇게하지 않을 것입니다. –

+0

@JonathanLeffler : 그건 사실이지만 C와 C++ interop을 좀 더 의심스럽게 만듭니다. 그렇죠? –

+0

왜 그것이 C 및 C++ 상호 운용성에 영향을 미치는지 확신 할 수 없습니다. AFAIK, 당신은 C++에서 C, AFAIK (modulo 네임 스페이스, 그러나 그것은 당면한 이슈에 접선)에서와 똑같이 선언 할 수 있습니다. 필자는'struct MyStruct'와'MyHandle'에 대해 별도의 이름을 사용했습니다 ... 왜냐하면'typedef struct MyHandle * MyHandle; '은 저에게 혐오스럽고 아마도 C++ 컴파일러에서 정신 분열증을 일으킬 것입니다. –

0

몇 가지 차이점이 있습니다. 한 줄에 여러 개의 선언을하고 있다면

첫째, 다음 두 조각은 동일합니다 : 당신이 뭔가를 같이하려고 노력에서 의미 론적 문제로 실행 수 있기 때문에

char *c1, *c2, *c3, *c4; 

typedef char * charPtr; 
charPtr c1, c2, c3, c4; // I don't need to repeat the unary * everywhere 

이 부분에 유용합니다 :

char * c1, c2, c3, c4; // declares one char pointer and three chars 

둘째, 그들은 크게 거의 무한 추함과 더러움을위한 기회입니다 함수 포인터 유형의 정의를 단순화 할 수 있습니다.

float (*someCrazyFunction)(float(*)(), float) = foo; // WTF is this 

typedef float (*crazyFunction)(float(*)(), float); 
crazyFunction myCrazyFunction = foo; // easier to deal with 

Here's an ideone demonstrating all of this behavior.