mutually referential (Pg 140 K&R2)

Discussion in 'C Programming' started by G Patel, Apr 23, 2005.

  1. G Patel

    G Patel Guest

    Pg. 140 of K&R2 shows an example of mutually referential structure
    declarations...

    struct t
    {
    struct s *p;
    };

    struct s
    {
    struct t *q;
    };


    I ran the following test program through my C compiler to see if it
    would compile:

    #include <stdlib.h>

    struct t
    {
    struct s *p; /* type 'struct s' is not visible here */
    };

    struct s
    {
    struct t *q;
    };

    int main()
    {
    printf("Hello world\n");
    return 0;
    }


    It compiled and ran without any noticeable problems. I expected it to
    complain about the line I've commented above.

    How is this valid when the type 'struct s' is not in scope when *p is
    declared as a member of the type struct t?

    If this is 'valid' please tell me why scopes don't apply here. If this
    is 'not valid' please tell me how I can declare mutually referential
    struct types.

    Thank you
    G Patel, Apr 23, 2005
    #1
    1. Advertising

  2. G Patel

    Ken Human Guest

    G Patel wrote:
    > Pg. 140 of K&R2 shows an example of mutually referential structure
    > declarations...
    >
    > struct t
    > {
    > struct s *p;
    > };
    >
    > struct s
    > {
    > struct t *q;
    > };
    >
    >
    > I ran the following test program through my C compiler to see if it
    > would compile:
    >
    > #include <stdlib.h>
    >
    > struct t
    > {
    > struct s *p; /* type 'struct s' is not visible here */
    > };
    >
    > struct s
    > {
    > struct t *q;
    > };
    >
    > int main()
    > {
    > printf("Hello world\n");
    > return 0;
    > }
    >
    >
    > It compiled and ran without any noticeable problems. I expected it to
    > complain about the line I've commented above.
    >
    > How is this valid when the type 'struct s' is not in scope when *p is
    > declared as a member of the type struct t?
    >
    > If this is 'valid' please tell me why scopes don't apply here. If this
    > is 'not valid' please tell me how I can declare mutually referential
    > struct types.
    >
    > Thank you
    >


    The following code will place both structs in scope. The first "struct
    t;" is unnecessary, but it demonstrates the point.

    #include <stdio.h>

    struct s;
    struct t;

    struct t {
    struct s *p;
    };

    struct s {
    struct t *q;
    };

    int main(void) {
    printf("Hello world\n");
    return 0;
    }
    Ken Human, Apr 23, 2005
    #2
    1. Advertising

  3. G Patel

    Chris Torek Guest

    In article <>
    G Patel <> wrote:
    >Pg. 140 of K&R2 shows an example of mutually referential structure
    >declarations...


    [Vertically compressed]

    >struct t { struct s *p; };
    >struct s { struct t *q; };


    [snippage]

    >How is this valid when the type 'struct s' is not in scope when *p is
    >declared as a member of the type struct t?


    Structures -- which are C's general-purpose "create me a new type"
    thingy -- can be declared, as well as defined.

    The minimal syntax of such a declaration is:

    struct tag;

    while the minimal syntax of a definition that uses a tag[%] is:

    struct tag { FIRST_MEMBER; };

    In other words, without the open brace, you are merely mentioning
    the *name* of a type, rather than defining that type. (The contents
    inside the braces define the type itself.)

    [%footnote: New structure types can be left un-named by omitting
    the tag. This has relatively limited usefulness since the name
    cannot then be repeated. On the other hand, it is possible to
    "capture" the un-named type name using C's "typedef" keyword, which
    -- despite its name -- does not actually define new types. Instead,
    it defines aliases for existing types. If you capture the no-name
    type under some alternative alias, you can use the alias. It is
    a bit like referring to either Clark Kent as Superman: if Clark
    Kent had not had a real name, you would have had to call him Superman
    even when he was in disguise. :) ]

    Given a type-name, you can of course declare variables of that
    type, and pointers to that type, and so on:

    int i; /* this means "i" is an "int" */
    char *cp; /* this means *cp is a "char" */

    The same holds true for your own types:

    struct type1 s1; /* i.e., s1 is a "type1" */
    struct type2 *s2; /* i.e., *s2 is a "type2" */

    If you have already defined your type, this is fine; if you have
    not yet defined your type, it is what C calls an "incomplete type".
    You can sometimes, but not always, declare ordinary variables that
    have incomplete types; you can always declare pointers to incomplete
    types. (More specifically -- and more confusingly -- if T is an
    incomplete type, "T *", pointer-to-T, is itself a complete type.
    It merely points to an incomplete type.)

    >If this is 'valid' please tell me why scopes don't apply here.


    Scopes can in fact apply here:

    struct s { long l; };

    void f(void) {
    struct s; /* this "vacuous" declaration clears the way */

    struct s { char c; } var;
    /* this is a new, different type also named s */
    ...
    }

    Note, however, that the scope is introduced by the definition of
    function f(), not the braces around the structure members. (This
    is one area where C and C++ differ: in C++, structure members can
    have their own scope, limited to the structure. The C++ rules are
    much more complicated than the C rules.)

    I realize this is also confusing. I recommend never doing it, in
    the same way that I recommend against code like:

    int number_of_zorgs;
    void f(void) {
    int number_of_zorgs;
    ...
    }

    Here we have two ordinary "int" variables with the same name. It
    becomes confusing if we attempt to talk about both variables at
    the same time, since they both have the same name. (Since my own
    given name is quite common, I have a lot of personal experience
    with this problem. Sometimes I am in a group that has two or three
    "Chris"es in it. Sometimes people resort to numbering us.)

    With all that out of the way, let us revisit the mutually-referential
    structure issue. Given:

    struct s; /* declare type s without defining it */
    struct t; /* and likewise for type t */

    struct s { struct t *tp; }; /* now define s */
    struct t { struct s *sp; }; /* and t */

    it is easy enough to see that an "s" refers indirectly (via pointer)
    to a "t", and a "t" refers indirectly to an "s". We declared both
    ahead of time, and then defined both.

    C, however, allows us to be sloppy. A type-name simply springs
    into existence as soon as we mention it (using C's type-name-creating
    keyword "struct", of course). So we do not have to declare the
    two types in advance -- we can just start defining one, and declare
    the other in the middle of the first one's definition. This is
    what you had in your sample code.

    There are some problems with this. Typos sneak in, as pointed out
    in another thread earlier. If we declare or define a type called
    "gargleblaster", it is easy to mis-type the name as "garbleblaster"
    (garG => garB) at some point:

    struct gargleblaster; /* optionally, insert { contents } here too */
    ...
    extern void somefunc(struct garbleblaster *);

    We never declared (much less defined) the misspelled name, so it
    simply springs into existence as a new incomplete type. (Some use
    this as an argument for using typedefs; and it is a valid argument
    for that, despite my own tastes running the other way.)

    Structure types *do* obey scopes (despite having none of their
    own). In general, incomplete structure types are only usefully
    completed in the same scope (it is possible to complete them in an
    inner scope, but this has relatively little practical application).
    Unfortunately for this particular case, function prototype arguments
    have "prototype scope", which ends -- and can never be resurrected
    -- at the close parenthesis ending the prototype sequence. Thus
    the declaration of function somefunc() declares an incomplete type
    ("garbleblaster", our misspelled "gargleblaster") that can never
    be completed. Better compilers generally produce a warning here.
    The warning is, however, confusing until you understand this whole
    paragraph.
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, Apr 23, 2005
    #3
  4. G Patel

    Russell Shaw Guest

    G Patel wrote:
    > Pg. 140 of K&R2 shows an example of mutually referential structure
    > declarations...
    >
    > struct t
    > {
    > struct s *p;
    > };
    >
    > struct s
    > {
    > struct t *q;
    > };
    >
    >
    > I ran the following test program through my C compiler to see if it
    > would compile:
    >
    > #include <stdlib.h>
    >
    > struct t
    > {
    > struct s *p; /* type 'struct s' is not visible here */
    > };
    >
    > struct s
    > {
    > struct t *q;
    > };
    >
    > int main()
    > {
    > printf("Hello world\n");
    > return 0;
    > }
    >
    >
    > It compiled and ran without any noticeable problems. I expected it to
    > complain about the line I've commented above.
    >
    > How is this valid when the type 'struct s' is not in scope when *p is
    > declared as a member of the type struct t?
    >
    > If this is 'valid' please tell me why scopes don't apply here. If this
    > is 'not valid' please tell me how I can declare mutually referential
    > struct types.


    struct s *p declares p using an incomplete struct s type, which is later completed
    with struct s {...}. Incomplete types apply only to curly bracket things like
    enums, unions, and structs iirc.
    Russell Shaw, Apr 23, 2005
    #4
  5. On 22 Apr 2005 21:13:49 -0700, "G Patel" <> wrote:

    >Pg. 140 of K&R2 shows an example of mutually referential structure
    >declarations...
    >
    >struct t
    >{
    > struct s *p;
    >};
    >
    >struct s
    >{
    > struct t *q;
    >};
    >
    >
    >I ran the following test program through my C compiler to see if it
    >would compile:
    >
    >#include <stdlib.h>
    >
    >struct t
    >{
    > struct s *p; /* type 'struct s' is not visible here */
    >};
    >
    >struct s
    >{
    > struct t *q;
    >};
    >
    >int main()
    >{
    > printf("Hello world\n");
    > return 0;
    >}
    >
    >
    >It compiled and ran without any noticeable problems. I expected it to
    >complain about the line I've commented above.
    >
    >How is this valid when the type 'struct s' is not in scope when *p is
    >declared as a member of the type struct t?
    >
    >If this is 'valid' please tell me why scopes don't apply here. If this
    >is 'not valid' please tell me how I can declare mutually referential
    >struct types.
    >


    The fact that you compiler does not generate a diagnostic has no
    bearing on whether the code is valid or not. The opposite is also
    true. The compiler is allowed to generate a diagnostic even if the
    code is perfectly valid.

    Maybe you should raise the warning level on your compiler.

    Maybe your compiler is defective in this area.

    Maybe it is an extension your compiler provides. Can you disable
    extensions?


    <<Remove the del for email>>
    Barry Schwarz, Apr 23, 2005
    #5
  6. G Patel

    Joe Estock Guest

    G Patel wrote:
    > Pg. 140 of K&R2 shows an example of mutually referential structure
    > declarations...
    >
    > struct t
    > {
    > struct s *p;
    > };
    >
    > struct s
    > {
    > struct t *q;
    > };
    >
    >
    > I ran the following test program through my C compiler to see if it
    > would compile:
    >
    > #include <stdlib.h>
    >
    > struct t
    > {
    > struct s *p; /* type 'struct s' is not visible here */
    > };
    >
    > struct s
    > {
    > struct t *q;
    > };
    >
    > int main()
    > {
    > printf("Hello world\n");
    > return 0;
    > }
    >
    >
    > It compiled and ran without any noticeable problems. I expected it to
    > complain about the line I've commented above.
    >
    > How is this valid when the type 'struct s' is not in scope when *p is
    > declared as a member of the type struct t?
    >
    > If this is 'valid' please tell me why scopes don't apply here. If this
    > is 'not valid' please tell me how I can declare mutually referential
    > struct types.
    >
    > Thank you
    >

    What everyone here is trying to say is you should forward-declare the
    struct before you use it in this case. See below for an example.

    struct s; /* forward-declare the struct we will define later */

    struct t
    {
    struct s *p;
    };

    struct s
    {
    struct t *q;
    };

    The above is an example of the "right way".

    Joe Estock
    Joe Estock, Apr 23, 2005
    #6
  7. Chris Torek wrote:
    > Scopes can in fact apply here:
    >
    > struct s { long l; };
    >
    > void f(void) {
    > struct s; /* this "vacuous" declaration clears the way */
    >
    > struct s { char c; } var;
    > /* this is a new, different type also named s */
    > ...
    > }


    In this example the vacuous declaration doesn't make any difference;
    the inner "full" declaration is valid and declares a type distinct
    from the outer declaration regardless. The vacuous declaration is
    needed when you want a name in an inner scope to match a tag defined
    in the (same) inner scope instead of a tag from the outer scope.

    struct f { long l; };

    void h(void) {
    struct f; /* "vacuous" declaration */

    struct g { struct f *p; };
    struct f { char p };
    }

    If the vacuous declaration were omitted `p' would be a pointer to a
    struct of the outer "f" type; the vacuous declaration hides the outer
    struct declaration and introduces a new type that is completed later
    on within the inner scope. Following the vacuous declaration all
    references to "struct f" within the block refer to this inner type.

    I can't think of a situation where this would actually be useful; it's
    always more straightforward to give the inner struct a distinct name.

    > In general, incomplete structure types are only usefully completed
    > in the same scope (it is possible to complete them in an inner
    > scope, but this has relatively little practical application).


    I don't think there is a way to complete incomplete structure types in
    an inner scope.

    Jeremy.
    Jeremy Yallop, Apr 23, 2005
    #7
  8. G Patel

    Chris Torek Guest

    >Chris Torek wrote:
    >> struct s { long l; };
    >> void f(void) {
    >> struct s; /* this "vacuous" declaration clears the way */
    >> struct s { char c; } var;
    >> /* this is a new, different type also named s */
    >> ...
    >> }


    In article <d4e4hq$ifh$7even.com>
    Jeremy Yallop <> wrote:
    >In this example the vacuous declaration doesn't make any difference;
    >the inner "full" declaration is valid and declares a type distinct
    >from the outer declaration regardless. The vacuous declaration is
    >needed when you want a name in an inner scope to match a tag defined
    >in the (same) inner scope instead of a tag from the outer scope.


    Ah, yes, I believe you are correct.

    [snippage]

    >> In general, incomplete structure types are only usefully completed
    >> in the same scope (it is possible to complete them in an inner
    >> scope, but this has relatively little practical application).


    >I don't think there is a way to complete incomplete structure types in
    >an inner scope.


    This does seem to be the case (i.e., given an incomplete "struct
    X" at some outer scope, any attempt to complete it at any nested
    scope will instead define a new type of the same name).

    To generalize: the vacuous (empty/forward) declarations of struct
    tags is often not required, but never actually harmful. It is
    required if you are overriding an outer-scope name for mutually
    referential structures limited to some inner scope, and it is often
    required if you want to have prototype arguments using a type that
    will not be defined (i.e., will be left incomplete):

    /* interface.h */

    struct bob; /* required */

    void raise_bob(struct bob *);
    void lower_bob(struct bob *);
    void move_bob_sideways(struct bob *, int);

    but:

    /* other_interface.h */

    /* struct jane; -- allowed but not required */

    struct jane *new_jane(void);
    void move_jane_sideways(struct jane *, int);

    Here the first mention of the type "jane" occurs outside a prototype,
    at the outermost scope, so it springs into being at that point and
    the declaration of the function move_jane_sideways() refers to the
    existing, incomplete type.

    One can either learn all these rules, or just write out the vacuous
    declarations. :)

    If you like typedefs, or are commanded :) to use them, I recommend
    writing out all the typedef sequences first:

    typedef struct bob BOB;
    typedef struct plumb PLUMB;

    /* optional: now complete it */
    struct bob {
    BOB *list_of_bobs;
    PLUMB *parent;
    ... fill this in ...
    };

    void move_bob_sideways(BOB *, int);

    Note that by listing all the types first, and giving them all
    their aliases -- you can do this with the "value meal combo deal"
    construct above, or by writing it all out:

    struct bob;
    typedef struct bob BOB;

    struct plumb;
    typedef struct plumb PLUMB;

    -- by giving them their aliases *before* you define them, you
    are able to use the aliases inside the definition.
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, Apr 23, 2005
    #8
  9. On Fri, 22 Apr 2005 22:36:14 -0700, Barry Schwarz wrote:

    > On 22 Apr 2005 21:13:49 -0700, "G Patel" <> wrote:


    ....

    >>I ran the following test program through my C compiler to see if it
    >>would compile:
    >>
    >>#include <stdlib.h>


    You don't need <stdlib.h> for this code but you do need to #include
    <stdio.h> since the code uses printf().

    >>struct t
    >>{
    >> struct s *p; /* type 'struct s' is not visible here */
    >>};
    >>
    >>struct s
    >>{
    >> struct t *q;
    >>};
    >>
    >>int main()
    >>{
    >> printf("Hello world\n");
    >> return 0;
    >>}
    >>
    >>
    >>It compiled and ran without any noticeable problems. I expected it to
    >>complain about the line I've commented above.
    >>
    >>How is this valid when the type 'struct s' is not in scope when *p is
    >>declared as a member of the type struct t?
    >>
    >>If this is 'valid' please tell me why scopes don't apply here. If this
    >>is 'not valid' please tell me how I can declare mutually referential
    >>struct types.
    >>

    >
    > The fact that you compiler does not generate a diagnostic has no
    > bearing on whether the code is valid or not. The opposite is also
    > true. The compiler is allowed to generate a diagnostic even if the
    > code is perfectly valid.
    >
    > Maybe you should raise the warning level on your compiler.
    >
    > Maybe your compiler is defective in this area.


    If we add #include <stdio.h> the code is perfectly valid. I don't see any
    defect in the area under discussion.

    Lawrence
    Lawrence Kirby, Apr 25, 2005
    #9
  10. G Patel

    Old Wolf Guest

    Joe Estock wrote:
    > G Patel wrote:
    > > It compiled and ran without any noticeable problems.
    > > I expected it to complain

    >
    > What everyone here is trying to say is you should forward-declare
    > the struct before you use it in this case.


    What? You shouldn't forward-declare the struct, and the
    original code is perfectly fine.

    > struct s; /* forward-declare the struct we will define later */


    This line achieves nothing; the struct is automatically
    forward-declared the first time it is used, in this example.

    > struct t { struct s *p; };
    > struct s { struct t *q; };
    >
    > The above is an example of the "right way".


    The right way to write redundant code?
    Old Wolf, Apr 26, 2005
    #10
  11. G Patel

    CBFalconer Guest

    G Patel wrote:
    >
    > Pg. 140 of K&R2 shows an example of mutually referential structure
    > declarations...
    >
    > struct t
    > {
    > struct s *p;
    > };
    >
    > struct s
    > {
    > struct t *q;
    > };
    >
    >
    > I ran the following test program through my C compiler to see if it
    > would compile:
    >
    > #include <stdlib.h>
    >
    > struct t
    > {
    > struct s *p; /* type 'struct s' is not visible here */
    > };
    >
    > struct s
    > {
    > struct t *q;
    > };
    >
    > int main()
    > {
    > printf("Hello world\n");
    > return 0;
    > }
    >
    > It compiled and ran without any noticeable problems. I expected
    > it to complain about the line I've commented above.
    >
    > How is this valid when the type 'struct s' is not in scope when *p
    > is declared as a member of the type struct t?
    >
    > If this is 'valid' please tell me why scopes don't apply here. If
    > this is 'not valid' please tell me how I can declare mutually
    > referential struct types.


    To form those declared structures the compiler only needs to know
    the size of a pointer to a structure. In order to allow for
    mutually recursive data definitions of this sort, the C standard
    has a provision that states that all pointers to structures shall
    be the same size. However if you try to dereference that pointer
    before properly completing the definition, there will be errors.
    Meanwhile the compiler knows how much space to allocate for the
    pointer, and can carry on.

    --
    "If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers." - Keith Thompson
    CBFalconer, Apr 26, 2005
    #11
  12. On Sat, 23 Apr 2005 15:23:02 +1000, Russell Shaw
    <rjshawN_o@s_pam.netspace.net.au> wrote:
    <snip>
    > struct s *p declares p using an incomplete struct s type, which is later completed
    > with struct s {...}.


    Correct.

    > Incomplete types apply only to curly bracket things like
    > enums, unions, and structs iirc.


    YDNRC.

    Forward declared struct and union tags are incomplete, until (the end
    of) the full definition (if any). You can't forward declare an enum
    tag; technically an enum type is incomplete from its type-specifier to
    its closing brace, but this only means you can't use sizeof(enum foo)
    as one of its own values which seems pretty silly anyway.

    Array with unspecified bound is an incomplete type, which can be used
    to access an actual array defined elsewhere, which definition requires
    a bound and linkage requires static duration; or when used as a
    Flexible Array Member at the end of a struct in C99 can be used to
    access actual memory of varying sizes.

    'void' is an incomplete type that cannot be completed.

    - David.Thompson1 at worldnet.att.net
    Dave Thompson, May 2, 2005
    #12
  13. G Patel

    pete Guest

    Dave Thompson wrote:
    >
    > On Sat, 23 Apr 2005 15:23:02 +1000, Russell Shaw
    > <rjshawN_o@s_pam.netspace.net.au> wrote:
    > <snip>
    > > struct s *p declares p using an incomplete struct s type, which is later completed
    > > with struct s {...}.

    >
    > Correct.
    >
    > > Incomplete types apply only to curly bracket things like
    > > enums, unions, and structs iirc.

    >
    > YDNRC.
    >
    > Forward declared struct and union tags are incomplete, until (the end
    > of) the full definition (if any). You can't forward declare an enum
    > tag; technically an enum type is incomplete from its type-specifier to
    > its closing brace, but this only means you can't use sizeof(enum foo)
    > as one of its own values which seems pretty silly anyway.


    I think you can. The enum type is complete,
    that is to say that it's type size is known at compile time,
    even if it's values haven't been specified.

    /* BEGIN new.c */

    #include <stdio.h>

    int main(void)
    {
    enum foo {Zero = sizeof (enum foo), One};
    enum bar;

    printf("sizeof (enum bar) is %lu bytes\n.",
    (long unsigned)sizeof(enum bar));
    return One - Zero - 1;
    }

    /* END new.c */


    --
    pete
    pete, May 2, 2005
    #13
  14. pete <> writes:
    > Dave Thompson wrote:

    [...]
    >> Forward declared struct and union tags are incomplete, until (the end
    >> of) the full definition (if any). You can't forward declare an enum
    >> tag; technically an enum type is incomplete from its type-specifier to
    >> its closing brace, but this only means you can't use sizeof(enum foo)
    >> as one of its own values which seems pretty silly anyway.

    >
    > I think you can. The enum type is complete,
    > that is to say that it's type size is known at compile time,
    > even if it's values haven't been specified.
    >
    > /* BEGIN new.c */
    >
    > #include <stdio.h>
    >
    > int main(void)
    > {
    > enum foo {Zero = sizeof (enum foo), One};
    > enum bar;
    >
    > printf("sizeof (enum bar) is %lu bytes\n.",
    > (long unsigned)sizeof(enum bar));
    > return One - Zero - 1;
    > }
    >
    > /* END new.c */


    No. C99 6.7.2.2p4 says:

    Each enumerated type shall be compatible with char, a signed
    integer type, or an unsigned integer type. The choice of type is
    implementation-defined, but shall be capable of representing
    the values of all the members of the enumeration. The enumerated
    type is incomplete until after the } that terminates the list of
    enumerator declarations.

    A footnote says:

    An implementation may delay the choice of which integer type until
    all enumeration constants have been seen.

    If your compiler accepts the above code (in conforming mode), it's
    probably broken. <OT>gcc doesn't.</OT>

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, May 2, 2005
    #14
  15. G Patel

    pete Guest

    Keith Thompson wrote:
    >
    > pete <> writes:
    > > Dave Thompson wrote:

    > [...]
    > >> Forward declared struct and union tags are incomplete, until (the end
    > >> of) the full definition (if any). You can't forward declare an enum
    > >> tag; technically an enum type is incomplete from its type-specifier to
    > >> its closing brace, but this only means you can't use sizeof(enum foo)
    > >> as one of its own values which seems pretty silly anyway.

    > >
    > > I think you can. The enum type is complete,
    > > that is to say that it's type size is known at compile time,
    > > even if it's values haven't been specified.
    > >
    > > /* BEGIN new.c */
    > >
    > > #include <stdio.h>
    > >
    > > int main(void)
    > > {
    > > enum foo {Zero = sizeof (enum foo), One};
    > > enum bar;
    > >
    > > printf("sizeof (enum bar) is %lu bytes\n.",
    > > (long unsigned)sizeof(enum bar));
    > > return One - Zero - 1;
    > > }
    > >
    > > /* END new.c */

    >
    > No. C99 6.7.2.2p4 says:
    >
    > Each enumerated type shall be compatible with char, a signed
    > integer type, or an unsigned integer type. The choice of type is
    > implementation-defined, but shall be capable of representing
    > the values of all the members of the enumeration. The enumerated
    > type is incomplete until after the } that terminates the list of
    > enumerator declarations.
    >
    > A footnote says:
    >
    > An implementation may delay the choice of which integer type until
    > all enumeration constants have been seen.
    >
    > If your compiler accepts the above code (in conforming mode), it's
    > probably broken. <OT>gcc doesn't.</OT>


    It's always distressing to learn something about C,
    but that's why I'm here.
    Thank you.

    --
    pete
    pete, May 2, 2005
    #15
    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. Colin JN Breame

    Mutually referential classes

    Colin JN Breame, Jan 21, 2004, in forum: C++
    Replies:
    5
    Views:
    403
    Colin JN Breame
    Jan 22, 2004
  2. Eric

    Re: Mutually referential types

    Eric, Aug 15, 2003, in forum: C Programming
    Replies:
    5
    Views:
    349
    Mark Haigh
    Aug 17, 2003
  3. Chris Torek

    Re: Mutually referential types

    Chris Torek, Aug 15, 2003, in forum: C Programming
    Replies:
    1
    Views:
    301
    Colin JN Breame
    Aug 16, 2003
  4. ganesh
    Replies:
    1
    Views:
    287
  5. jrwats
    Replies:
    6
    Views:
    342
    Zachary Turner
    Jan 18, 2009
Loading...

Share This Page