tags:

views:

286

answers:

3

I'm creating a C api that hides some functionality in a DLL file.

Since everything is C++ on the inside most of the functions works against handles which maps directly to this pointers on the inside of the API.

To get a some degree of type safety for those handles I define them like this:

typedef struct MyType1* MyType1Handle;
typedef struct MyType2* MyType2Handle;

I don't actually define MyType1 or MyType2 at any place since I only use them as pointers and do a type cast on the inside of the api to the actual pointer type.

My problem is that when using my library in a clr project in visual studio I get this warning: unresolved typeref token (token) for 'type'; image may not run.

http://msdn.microsoft.com/en-us/library/h8027ys9(VS.80).aspx

It's no big deal since it works, but it looks unprofessional.

I don't like using void*:

typedef void* MyType1Handle;
typedef void* MyType2Handle;

This makes it possible to call a function wanting a MyType1Handle with a MyType2Handle since they are actually the same type.

Another approach I don't want to use is something like this

typedef int MyType1Handle;
typedef int MyType2Handle;

This would work fine as long as int's and pointers have the same size, but that's not always the case and it seems like there is no foolproof way of getting a platform specific pointer sized integer. It has the same type safety problems as the void* as well.

Another approach I tried was to do it like this:

struct MyType1{};
typedef struct MyType1* MyType1Handle;

This didn't work in C since empty structs is invalid C code. I could of course extend my struct with a dummy member, but it seems like there should be a better way of doing this.

So my question boils down to:

How do you generally specify this kind of types in the most compatible way?

+10  A: 

If you look at how Microsoft defines it's winapi handles (winnt.h) it actually looks like this:

struct HWND__ { int unused; }; typedef struct HWND__ *HWND

in fact they have a macro for this:

#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name

so.. this seems to be a common practice to do so. Unfortunately I can't make another suggestion except this one, which you already mentioned, but I hope it helps you anyway.

lx
Thanks for the answer. It seems like I'm not the first one to run into this problem atleast :)
Laserallan
One difference here is that in the public headers, the HANDLE type references a concrete type. The fake struct is completely defined. Of course, they define DECLARE_HANDLE differently when including those files in the implementation.
RBerteig
+2  A: 

I think you can just declare, but not define, the source structures:

struct MyType1;

typedef struct MyType1* MyType1Handle;

JamieH
+1  A: 

Use an opaque struct. This is a good idea in many cases when defining the interface to a library in C: it improves modularity, hides unnecessary detail

As JamieH said, you get an opaque struct by declaring - but not defining - a struct. It's perfectly valid to have, and pass, pointers to the opaque struct into the libraries functions as arguments and return them as values. Users of library however cannot create or modify objects of the opaque struct since it's size and content is unknown.

The C standard library, and many others, already use this approach so it should be familiar. The cannonical example is the use of FILE *: fopen() creates and initialises the struct and returns a pointer to it, fclose() cleans up and releases it and all other i/o functions get their context from the passed in FILE *.

Wuggy