Does this confirm to ISO C?

Discussion in 'C Programming' started by МакÑим Фомин, Sep 11, 2011.

  1. I want to hide several fields within structure from "client" code. Can
    I use following (just example):

    - declare struct X { int visible; }; in "export.h" and several
    functions, which take struct X as an argument;
    - "export.h" is included by client code;
    - declare struct X { int visible; int hidden; }; in "private.h";
    - "private.h" is included in .c file which contains definitions of
    functions which work with struct X

    Thus, when mentioned functions process struct X, they may access to
    hidden integer, however external code even doesn't suspect that there
    is one.

    The first issue of this technique is that client code cannot hold
    allocation.
     
    МакÑим Фомин, Sep 11, 2011
    #1
    1. Advertising

  2. МакÑим Фомин

    Eric Sosman Guest

    On 9/11/2011 3:49 PM, МакÑим Фомин wrote:
    > I want to hide several fields within structure from "client" code. Can
    > I use following (just example):
    >
    > - declare struct X { int visible; }; in "export.h" and several
    > functions, which take struct X as an argument;
    > - "export.h" is included by client code;
    > - declare struct X { int visible; int hidden; }; in "private.h";
    > - "private.h" is included in .c file which contains definitions of
    > functions which work with struct X
    >
    > Thus, when mentioned functions process struct X, they may access to
    > hidden integer, however external code even doesn't suspect that there
    > is one.


    It's not guaranteed to work. True, the "visible" element will
    appear at the same offset in both versions of "struct X," and if
    "visible" actually encompasses several elements they will also appear
    at the same offsets as long as both versions agree.[*] But the two
    versions might have different alignment requirements -- not very
    likely in what you've shown, but change hidden to a "double" and it
    is entirely plausible that the complete "struct X" could require
    stricter alignment than the abbreviated version.

    [*] Actually, the Standard only *guarantees* this if the two
    versions both appear in the same union. But nobody's ever seen an
    actual compiler where it wouldn't hold, even without the union.

    Besides, there's a better way (which also avoids the confusion
    of having two different versions of "struct X" floating around).
    Use two different structs, one public and one private, and embed
    the public version inside the private:

    struct public {
    int visible;
    ...
    };

    struct private {
    struct public export;
    int hidden;
    FILE *stream;
    char *stuff;
    ...
    };

    Your library code should deal in "struct public *" pointers, which
    you know always point to the "export" element of a "struct private"
    instance. So internally

    void foo(struct public *bar) {
    struct private *baz = (struct private*)bar;
    baz->hidden = 42;
    }

    > The first issue of this technique is that client code cannot hold
    > allocation.


    The usual way to deal with this is to have the library manage
    the storage, and let the client deal only with pointers to it:

    struct public *factory(void) {
    struct private *baz = malloc(sizeof *baz);
    baz->stream = fopen("file.dat", "r");
    baz->stuff = malloc(42);
    ...
    return &baz->export;
    }

    void oubliette(struct public *junk) {
    struct private *baz = (struct private*)junk;
    fclose(baz->stream);
    free(baz->stuff);
    ...
    free(baz); // or free(junk) in simple cases
    }

    --
    Eric Sosman
    d
     
    Eric Sosman, Sep 11, 2011
    #2
    1. Advertising

  3. МакÑим Фомин <> wrote:
    > I want to hide several fields within structure from "client" code. Can
    > I use following (just example):


    > - declare struct X { int visible; }; in "export.h" and several
    > functions, which take struct X as an argument;
    > - "export.h" is included by client code;
    > - declare struct X { int visible; int hidden; }; in "private.h";
    > - "private.h" is included in .c file which contains definitions of
    > functions which work with struct X


    > Thus, when mentioned functions process struct X, they may access to
    > hidden integer, however external code even doesn't suspect that there
    > is one.


    > The first issue of this technique is that client code cannot hold
    > allocation.


    Looks extremely dirty to me, especially naming both the same.
    And yes, the user can't allocate such a structure, nor can he
    make copies - and there's nothing that would allow you to
    control that the client doesn't do it anyway and mess up your
    whole scheme. And you can only pass pointers to the struc-
    ture between your and the clients code (otherwise the client
    would need a full definition or things would get messed up
    completely if the clients code would receive a larger struc-
    ture than it is made to expect). Why not then simplify life
    a lot by making it a completely opaque structure and export a
    function that allows the client to set the visible member?
    While you're at it you could also supply a function for allo-
    cation and deallocation. Looks a lot safer to me and will cost
    you not much more than the work of adding a rather small number
    of functions. With a typedef you could even make it invisible
    to the client that it's dealing with just pointers to that
    kind of structures.
    Regards, Jens
    --
    \ Jens Thoms Toerring ___
    \__________________________ http://toerring.de
     
    Jens Thoms Toerring, Sep 11, 2011
    #3
  4. МакÑим Фомин <> writes:

    > I want to hide several fields within structure from "client" code. Can
    > I use following (just example):
    >
    > - declare struct X { int visible; }; in "export.h" and several
    > functions, which take struct X as an argument;
    > - "export.h" is included by client code;
    > - declare struct X { int visible; int hidden; }; in "private.h";
    > - "private.h" is included in .c file which contains definitions of
    > functions which work with struct X


    Just to clarify: you mean pointers to these structs will be passed, yes?
    You don't say so but without passing pointers it is certain to fail so
    it seems like a reasonable assumption.

    > Thus, when mentioned functions process struct X, they may access to
    > hidden integer, however external code even doesn't suspect that there
    > is one.
    >
    > The first issue of this technique is that client code cannot hold
    > allocation.


    If the allocation is "behind the wall" so to speak, have you considered:

    struct X { int visible; };

    struct Y { struct X x; int hidden; };

    The allocator makes a struct Y but passes &Y.x to the client. When the
    client passes &Y.x back to the other side of the wall, the conversion
    from struct X * back to struct Y * is certain to work.

    --
    Ben.
     
    Ben Bacarisse, Sep 11, 2011
    #4
  5. МакÑим Фомин

    Fred Guest

    On Sep 11, 2:58 pm, Ben Bacarisse <> wrote:
    > МакÑим Фомин <> writes:
    > > I want to hide several fields within structure from "client" code. Can
    > > I use following (just example):

    >
    > > - declare struct X { int visible; }; in "export.h" and several
    > > functions, which take struct X as an argument;
    > > - "export.h" is included by client code;
    > > - declare struct X { int visible; int hidden; }; in "private.h";
    > > - "private.h" is included in .c file which contains definitions of
    > > functions which work with struct X

    >
    > Just to clarify: you mean pointers to these structs will be passed, yes?
    > You don't say so but without passing pointers it is certain to fail so
    > it seems like a reasonable assumption.
    >
    > > Thus, when mentioned functions process struct X, they may access to
    > > hidden integer, however external code even doesn't suspect that there
    > > is one.

    >
    > > The first issue of this technique is that client code cannot hold
    > > allocation.

    >
    > If the allocation is "behind the wall" so to speak, have you considered:
    >
    >   struct X { int visible; };
    >
    >   struct Y { struct X x; int hidden; };
    >
    > The allocator makes a struct Y but passes &Y.x to the client.  When the
    > client passes &Y.x back to the other side of the wall, the conversion
    > from struct X * back to struct Y * is certain to work.
    >
    > --
    > Ben.


    And what happens if one declares an array of X's, then tries to
    access
    x[1].visible ?

    --
    Fred K
     
    Fred, Sep 12, 2011
    #5
  6. Fred <> writes:

    > On Sep 11, 2:58 pm, Ben Bacarisse <> wrote:
    >> МакÑим Фомин <> writes:
    >> > I want to hide several fields within structure from "client" code. Can
    >> > I use following (just example):

    >>
    >> > - declare struct X { int visible; }; in "export.h" and several
    >> > functions, which take struct X as an argument;
    >> > - "export.h" is included by client code;
    >> > - declare struct X { int visible; int hidden; }; in "private.h";
    >> > - "private.h" is included in .c file which contains definitions of
    >> > functions which work with struct X

    >>
    >> Just to clarify: you mean pointers to these structs will be passed, yes?
    >> You don't say so but without passing pointers it is certain to fail so
    >> it seems like a reasonable assumption.
    >>
    >> > Thus, when mentioned functions process struct X, they may access to
    >> > hidden integer, however external code even doesn't suspect that there
    >> > is one.

    >>
    >> > The first issue of this technique is that client code cannot hold
    >> > allocation.

    >>
    >> If the allocation is "behind the wall" so to speak, have you considered:
    >>
    >>   struct X { int visible; };
    >>
    >>   struct Y { struct X x; int hidden; };
    >>
    >> The allocator makes a struct Y but passes &Y.x to the client.  When the
    >> client passes &Y.x back to the other side of the wall, the conversion
    >> from struct X * back to struct Y * is certain to work.
    >>
    >> --
    >> Ben.


    It's better to snip sigs.

    > And what happens if one declares an array of X's, then tries to
    > access
    > x[1].visible ?


    Exactly what you'd expect happens. I know that was a rhetorical
    question but I'm not sure what else to say. Yes, arrays don't work with
    this scheme, but they won't work with any scheme where the size of the
    actual allocation is hidden from the "client" side. Presumably the OP
    accepts that restriction and would use and array of pointers instead.

    --
    Ben.
     
    Ben Bacarisse, Sep 12, 2011
    #6
  7. МакÑим Фомин

    Eric Sosman Guest

    On 9/12/2011 3:01 PM, Ben Bacarisse wrote:
    > Fred<> writes:
    >
    >> On Sep 11, 2:58 pm, Ben Bacarisse<> wrote:
    >>> МакÑим Фомин<> writes:
    >>>> I want to hide several fields within structure from "client" code. Can
    >>>> I use following (just example):
    >>>
    >>>> - declare struct X { int visible; }; in "export.h" and several
    >>>> functions, which take struct X as an argument;
    >>>> - "export.h" is included by client code;
    >>>> - declare struct X { int visible; int hidden; }; in "private.h";
    >>>> - "private.h" is included in .c file which contains definitions of
    >>>> functions which work with struct X
    >>>
    >>> Just to clarify: you mean pointers to these structs will be passed, yes?
    >>> You don't say so but without passing pointers it is certain to fail so
    >>> it seems like a reasonable assumption.
    >>>
    >>>> Thus, when mentioned functions process struct X, they may access to
    >>>> hidden integer, however external code even doesn't suspect that there
    >>>> is one.
    >>>
    >>>> The first issue of this technique is that client code cannot hold
    >>>> allocation.
    >>>
    >>> If the allocation is "behind the wall" so to speak, have you considered:
    >>>
    >>> struct X { int visible; };
    >>>
    >>> struct Y { struct X x; int hidden; };
    >>>
    >>> The allocator makes a struct Y but passes&Y.x to the client. When the
    >>> client passes&Y.x back to the other side of the wall, the conversion
    >>> from struct X * back to struct Y * is certain to work.

    >
    >> And what happens if one declares an array of X's, then tries to
    >> access
    >> x[1].visible ?

    >
    > Exactly what you'd expect happens. I know that was a rhetorical
    > question but I'm not sure what else to say. Yes, arrays don't work with
    > this scheme, but they won't work with any scheme where the size of the
    > actual allocation is hidden from the "client" side. Presumably the OP
    > accepts that restriction and would use and array of pointers instead.


    This is one reason the "visible" part is often entirely empty,
    so the caller gets a pointer to a completely opaque object (formally,
    an "incomplete type") and cannot possibly create a free-standing
    instance on his own.

    True, given a `struct X*' the caller cannot then access its
    "visible" member(s). Instead of just peeking and poking at those
    elements the caller must resort to accessor functions provided by
    the library, "getters and setters" as our O-O friends might say.
    That's a disadvantage, but usually not a crippling disadvantage.

    --
    Eric Sosman
    d
     
    Eric Sosman, Sep 13, 2011
    #7
  8. Thank to everybody for clarification!
     
    МакÑим Фомин, Sep 13, 2011
    #8
  9. МакÑим Фомин

    Phil Carmody Guest

    Eric Sosman <> writes:
    > On 9/12/2011 3:01 PM, Ben Bacarisse wrote:
    > This is one reason the "visible" part is often entirely empty,
    > so the caller gets a pointer to a completely opaque object (formally,
    > an "incomplete type") and cannot possibly create a free-standing
    > instance on his own.


    It's a minor nit, but I think I'd prefer to say that there
    was no visible part in such a situation, rather than the
    visible part being empty. The mathematician in me disagrees
    with the rest of me, of course.

    Phil
    --
    "Religion is what keeps the poor from murdering the rich."
    -- Napoleon
     
    Phil Carmody, Sep 15, 2011
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Franck DARRAS
    Replies:
    12
    Views:
    668
    Jim Higson
    Aug 23, 2004
  2. Alexei Polkhanov
    Replies:
    11
    Views:
    2,496
  3. Replies:
    13
    Views:
    6,520
    Dave Thompson
    Dec 20, 2004
  4. ISO C89 and ISO C99

    , Dec 10, 2004, in forum: C Programming
    Replies:
    18
    Views:
    564
    Dave Thompson
    Dec 20, 2004
  5. James Mills

    GSM to ISO / UCS2 to ISO

    James Mills, Aug 16, 2010, in forum: Python
    Replies:
    0
    Views:
    496
    James Mills
    Aug 16, 2010
Loading...

Share This Page