Path: utzoo!attcan!uunet!munnari.oz.au!goanna!ok From: ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) Newsgroups: comp.lang.c Subject: Re: A dilemma with handles Message-ID: <3877@goanna.cs.rmit.oz.au> Date: 3 Oct 90 01:41:33 GMT References: Distribution: comp Organization: Comp Sci, RMIT, Melbourne, Australia Lines: 55 In article , markd@iti.org (Mark Delany) writes: > Now my question relates to the definition of "handle". Within the > library this is simply a pointer to a structure that holds all the > goodies necessary to achieve the results. Remember that C allows you to use "incomplete types". You can have a header file /* pubstuff.h */ typedef struct BlackMystery *handle; extern handle zzopen(char *title, char *mode); ... /* end of pubstuff.h */ which your users can get at, and a header file /* realstuff.h */ #include "pubstuff.h" struct BlackMystery { /* system-dependent stuff spelled out here */ }; /* other declarations */ /* end of realstuff.h */ and then the file in which you implement, say, zzopen can #include "realstuff.h" When a user program #includes "pubstuff.h" they get handles which are pointers to an incomplete type. However, the C compiler will know everything that it needs to manage these pointers, because "all struct pointers smell the same". There are some big advantages to doing it this way. - you don't have to tell any lies; just conceal some of the truth - you don't need any casts - Lint remains your friend: When you Lint user code against your library there won't have been any casts needed, so you _will_ benefit from type checking - user code will be unable to declare variables of type struct BlackMystery, and it will be unable to deference handles. For example, given handle p, q; the assignment p = q; will be allowed and will work correctly, but *p = *q; will be disallowed and rejected at compile time. This approach isn't a _dummy_ declaration, just an _incomplete_ one. -- Fixed in the next release.