simple question about typedefs....

S

SpreadTooThin

extern DNSServiceCreateConnection(DNSServiceRef *sdRef);

typedef struct _DNSServiceRef_t *DNSServiceRef;

This statement creates a type called DNSServiceRef, which is a pointer
to a structure???
But I have no idea what a _DNSServiceRef_t is...

DNSServiceRef r; // Is just an uninitialized pointer?

Am I correct in assuming that there is NO such structure as a
_DNSServiceRef_t or that it is meant to be 'opaque' to me?

I'm asking because I'm trying to port this c/c++ code into another
language and I need to be sure I understand the data types being
passed....

_DNSServiceRef_t i;
_DNSServiceRef_t *p = &i; // Which is the same as DNSServiceRef p =
&i;
DNSServiceCreateConnection(&p);
 
T

Timothy Madden

extern DNSServiceCreateConnection(DNSServiceRef *sdRef);

typedef struct _DNSServiceRef_t *DNSServiceRef;
I think the order of this two lines should be reversed or else they will
not compile
This statement creates a type called DNSServiceRef, which is a pointer
to a structure???
But I have no idea what a _DNSServiceRef_t is...

DNSServiceRef r; // Is just an uninitialized pointer?

Yes, exactly, DNSServiceRef is a pointer to a structure, and you have no
ideea what the structure, _DSNServiceRef_t, is.

Actually you can tell, if you want, that _DNSServiceRef_t must be some
class/struct type.
Am I correct in assuming that there is NO such structure as a
_DNSServiceRef_t or that it is meant to be 'opaque' to me?

The language says that there /is/ such a structure, it is just that you
do not have its definition yet. This is called an incomplete type, and
you can legally make use of it, but only in stupidly limited ways.

Mostly to:
- declare and initialize, but not use, references of type
_DNSServiceRef_t &,
and
- to declare and use, but never dereference, pointers of type
_DNSServiceRef_t *
(all of these also with any const/volatile qualifications if needed).

The idea is that at any time later in the source file you can maybe
complete the type by providing the definition, and if you do that, than
all previous references/pointers constructed with the incomplete type
can now suddenly be used normally.

Although incomplete types may seem so very limited, they are the only
way to construct a class A that has a member pointer to some class B,
which in turn has a member pointer back to class A. I think this makes
incomplete types very important in the language.
I'm asking because I'm trying to port this c/c++ code into another
language and I need to be sure I understand the data types being
passed....

_DNSServiceRef_t i;
_DNSServiceRef_t *p =&i; // Which is the same as DNSServiceRef p =
&i;
DNSServiceCreateConnection(&p);
About this code, you should know that you can never write
_DNSServiceRef_t i;
unless _DNSServiceRef_t is a complete (or completed) type.

Otherwise, indeed
_DNSServiceRef_t *p = &i
is the same as
DNSServerviceRef p = &i;

About the type being opaque, if this code is from some library header
that never defines _DNSServiceRef_t, they yes, you can only treat the
type as opaque.

There is a distinction to make, though: the type actually is defined,
but only inside the library. This means you should never attempt to
complete the type by providing some definition yourself, unless you have
some known way to provide exactly the same definition provided in the
library (this is called the one definition rule).

This is a nice way to hide an implementation from its public interface,
without the implementation having to cast to and from void * all the time.

Hope that helps,
Timothy Madden
 
S

SpreadTooThin

Hope that helps,
Timothy Madden

It helps a great deal. I'll just restate this to see if I'm clear....

to simplify:

typedef void *DNSServiceRef; // would also have done the same job?

extern DNSServiceCreateConnection(DNSServiceRef *sdRef);
extern DNSServiceCreateConnection(void ** p); // is identical to
above?

I think what is happening here is that the library is allocating
memory for the 'opaque' structure and given the address of my pointer,
it sets the contents of my pointer to point to the memory it
allocated.

so to call the function...

void *p;
DNSServiceCreateConnection(&p); // would do the same trick.
 
T

Timothy Madden

It helps a great deal. I'll just restate this to see if I'm clear....

to simplify:

typedef void *DNSServiceRef; // would also have done the same job?

extern DNSServiceCreateConnection(DNSServiceRef *sdRef);
extern DNSServiceCreateConnection(void ** p); // is identical to
above?

I think what is happening here is that the library is allocating
memory for the 'opaque' structure and given the address of my pointer,
it sets the contents of my pointer to point to the memory it
allocated.

so to call the function...

void *p;
DNSServiceCreateConnection(&p); // would do the same trick.

Yes, you are quite right !

The library, having the definition, can allocate the structure, and do
whatever it wants with it, then return it to user code. User code then
has to follow the limitations for incomplete types, which in short
ensure that the code can only work with the address of the structure,
while the content remains untouchable. In this way the structure remains
private to the library, although it may look like the user code also
receives it

void is also an incomplete type (except that unlike other incomplete
types, void can never be completed by providing some definition), and
would also do the same job.

The difference, when using void *, is that the library implementation
would then have to cast back and forth between _DNSServiceRef_t * and
void * in every function where it receives the address back from user
code, or returns it to user code. That is why I said that incomplete
types are nice why to hide the implementation, as they are nicer than a
void * is for this purpose.

You do not necessarily need to use a typedef for the incomplete type.
The simple declaration
struct _DNSServiceRef_t;
just introduces the new incomplete type (you can complete it at any time
later). And also the following function declaration:
struct ResultT &funct(struct ParmListT &lst);
is equivalent with
struct Result;
struct ParamListT;

ResultT &funct(ParamListT &);
that is, the long function declaration will also introduce the two new
incomplete types, other then introducing the function.

Also, inside a class, a declaration like
friend class SiblingClass;
can be used to introduce the name SiblingClass, as an incomplete class,
if the name is not already declared and known, but it is introduced and
made visible only inside the class granting friendship. Then the friend
declaration also grants friendship to the newly class. After the
declaration, SiblingClass is an incomplete type that can now be used as
such, even if its definition appears in the source code way after the
class granting friendship.

Have fun
Timothy Madden
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,151
Latest member
JaclynMarl
Top