🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.std.c
Article #4385

Re: "Size not needed?"

#4385
From: Richard Krehbiel
Date: Mon, 20 Nov 1995 12:55
108 lines
3749 bytes
erik@kroete2.freinet.de (Erik Corry) wrote:

>One thing I'd like to be able to do, but can't (tested with gcc)
>is to have a header file with the following:

>   /*
>    * Erik's semi-complete types suggestion
>    */

>   /* This struct is unknown outside the library */

>   typedef struct private_part_s private_part;

>   /* This struct is known outside the library and (together with
>    * the functions) describes the interface to the library
>    */

>   typedef struct public_part_s
>   {
>     int x;
>     int y;
>   } public_part;

>   /*
>    * This struct is semi-complete, ie. it is incomplete, but you
>    * can do '->pub' on a pointer to it.
>    */

>   typedef struct my_object_s
>   {
>     public_part  pub;
>     private_part priv;      /* fails with incomplete type error */
>   } my_object;
>   
>What I'd like is for my_object to be a semi-complete type, where
>the size is unknown (so the whole fragile base 'class' problem is
>avoided), but a few of the elements are accessible (these could
>also be function pointers). This enables you to specify library
>interfaces which have a lot of OO features and are robust in terms of
>binary compatibility (since the size of the object cannot be used
>by the client code, the library implementer is never prevented from
>expanding the structure/interface).

Ah, here I may be able to help.  I've used this technique with
success.

The public header:

--- public.h ---
  typedef struct public_part_s
  {
    int x;
    int y;
  } public_part;
----------------

This is all that is exported.  The implementation then uses:

#include "public.h"

typedef struct private_whole_s
{
    public_part pub; /* publicly known members */
    int q, r, s;     /* privately known members */
} private_whole;

Now the library creates and uses private_whole for itself.  When
passing a pointer to a library caller, it passes a pointer to the
public_part...

public_part *new_public_part(void)
{
   private_whole *pv;
   pv = (private_whole *)calloc(sizeof(*pv), 1);
   if(pv == NULL)
      return NULL;
   /* initialize members... */
   return &pv->pub; /* Caller gets public part handle */
}

When the library receives a pointer to a public_part from a library
user, it casts it to a private_whole:

void operate(public_part *pub)
{
    private_whole *pv = (private_whole *)pub;

    /* operate on pv-> members */
}

The standard requires that a pointer to the first member of a struct
must equal a pointer to the struct, therefore this is sanctioned.

Well, actually I'd probably use a macro that I've declared for my own
use...

#define CONTAINER_P(p,s,m) (s*)((char *)(p)-offsetof(s,m))

...which, for pointer p which is assumed to be a pointer to member m
of aggregate s, gives a pointer to s.  There's a slight bit more type
checking than the simple cast (I'd love it if I could also be assured
that p is really the same type as &s.m).  If the member is first,
typically the subtraction is optimized away since the offset is a
constant zero.

--
Richard Krehbiel, Kastle Systems, Arlington VA USA
rich@kastle.com (work) or richk@cais.com (personal)
Technical Details
Message-ID: <1995Nov20.125350.9627@friend.kastle.com>
Path: arc1-ca.pugleaf.net!uu4news.netcom.com!friend!news
References: <48gu0r$91o@news0.rain.rg.net> <1995Nov17.120551.23493@friend.kastle.com> <48iljp$jl5@news0.rain.rg.net> <DI9nH2.DIy@kroete2.freinet.de>

Show Full Headers
Complete Article Headers
Newsgroups: comp.std.c
Path: arc1-ca.pugleaf.net!uu4news.netcom.com!friend!news
From: rich@kastle.com (Richard Krehbiel)
Subject: Re: "Size not needed?"
Message-ID: <1995Nov20.125350.9627@friend.kastle.com>
Sender: news@friend.kastle.com (News)
Reply-To: rich@kastle.com
Organization: Kastle Development Associates
X-Newsreader: Forte Free Agent 1.0.82
References: <48gu0r$91o@news0.rain.rg.net> <1995Nov17.120551.23493@friend.kastle.com> <48iljp$jl5@news0.rain.rg.net> <DI9nH2.DIy@kroete2.freinet.de>
Date: Mon, 20 Nov 1995 12:55:05 GMT