mutually referential (Pg 140 K&R2)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • G Patel

    mutually referential (Pg 140 K&R2)

    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

  • Ken Human

    #2
    Re: mutually referential (Pg 140 K&amp;R2)

    G Patel wrote:[color=blue]
    > 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
    >[/color]

    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;
    }

    Comment

    • Chris Torek

      #3
      Re: mutually referential (Pg 140 K&amp;R2)

      In article <1114229629.190 110.245990@g14g 2000cwa.googleg roups.com>
      G Patel <gaya.patel@gma il.com> wrote:[color=blue]
      >Pg. 140 of K&R2 shows an example of mutually referential structure
      >declarations.. .[/color]

      [Vertically compressed]
      [color=blue]
      >struct t { struct s *p; };
      >struct s { struct t *q; };[/color]

      [snippage]
      [color=blue]
      >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?[/color]

      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.)
      [color=blue]
      >If this is 'valid' please tell me why scopes don't apply here.[/color]

      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 "garbleblas ter"
      (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.

      Comment

      • Russell Shaw

        #4
        Re: mutually referential (Pg 140 K&amp;R2)

        G Patel wrote:[color=blue]
        > 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.[/color]

        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.

        Comment

        • Barry Schwarz

          #5
          Re: mutually referential (Pg 140 K&amp;R2)

          On 22 Apr 2005 21:13:49 -0700, "G Patel" <gaya.patel@gma il.com> wrote:
          [color=blue]
          >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.
          >[/color]

          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>>

          Comment

          • Joe Estock

            #6
            Re: mutually referential (Pg 140 K&amp;R2)

            G Patel wrote:[color=blue]
            > 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
            >[/color]
            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

            Comment

            • Jeremy Yallop

              #7
              Re: mutually referential (Pg 140 K&amp;R2)

              Chris Torek wrote:[color=blue]
              > 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 */
              > ...
              > }[/color]

              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.
              [color=blue]
              > 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).[/color]

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

              Jeremy.

              Comment

              • Chris Torek

                #8
                Re: mutually referential (Pg 140 K&amp;R2)

                >Chris Torek wrote:[color=blue][color=green]
                >> 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 */
                >> ...
                >> }[/color][/color]

                In article <d4e4hq$ifh$1@n ews.e7even.com>
                Jeremy Yallop <jeremy@jdyallo p.freeserve.co. uk> wrote:[color=blue]
                >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.[/color]

                Ah, yes, I believe you are correct.

                [snippage]
                [color=blue][color=green]
                >> 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).[/color][/color]
                [color=blue]
                >I don't think there is a way to complete incomplete structure types in
                >an inner scope.[/color]

                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(struc t bob *);
                void lower_bob(struc t bob *);
                void move_bob_sidewa ys(struct bob *, int);

                but:

                /* other_interface .h */

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

                struct jane *new_jane(void) ;
                void move_jane_sidew ays(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_sidew ays() 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_sidewa ys(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.

                Comment

                • Lawrence Kirby

                  #9
                  Re: mutually referential (Pg 140 K&amp;R2)

                  On Fri, 22 Apr 2005 22:36:14 -0700, Barry Schwarz wrote:
                  [color=blue]
                  > On 22 Apr 2005 21:13:49 -0700, "G Patel" <gaya.patel@gma il.com> wrote:[/color]

                  ....
                  [color=blue][color=green]
                  >>I ran the following test program through my C compiler to see if it
                  >>would compile:
                  >>
                  >>#include <stdlib.h>[/color][/color]

                  You don't need <stdlib.h> for this code but you do need to #include
                  <stdio.h> since the code uses printf().
                  [color=blue][color=green]
                  >>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.
                  >>[/color]
                  >
                  > 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.[/color]

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

                  Lawrence

                  Comment

                  • Old Wolf

                    #10
                    Re: mutually referential (Pg 140 K&amp;R2)

                    Joe Estock wrote:[color=blue]
                    > G Patel wrote:[color=green]
                    > > It compiled and ran without any noticeable problems.
                    > > I expected it to complain[/color]
                    >
                    > What everyone here is trying to say is you should forward-declare
                    > the struct before you use it in this case.[/color]

                    What? You shouldn't forward-declare the struct, and the
                    original code is perfectly fine.
                    [color=blue]
                    > struct s; /* forward-declare the struct we will define later */[/color]

                    This line achieves nothing; the struct is automatically
                    forward-declared the first time it is used, in this example.
                    [color=blue]
                    > struct t { struct s *p; };
                    > struct s { struct t *q; };
                    >
                    > The above is an example of the "right way".[/color]

                    The right way to write redundant code?

                    Comment

                    • CBFalconer

                      #11
                      Re: mutually referential (Pg 140 K&amp;R2)

                      G Patel wrote:[color=blue]
                      >
                      > 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.[/color]

                      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.c om, 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


                      Comment

                      • Dave Thompson

                        #12
                        Re: mutually referential (Pg 140 K&amp;R2)

                        On Sat, 23 Apr 2005 15:23:02 +1000, Russell Shaw
                        <rjshawN_o@s_pa m.netspace.net. au> wrote:
                        <snip>[color=blue]
                        > struct s *p declares p using an incomplete struct s type, which is later completed
                        > with struct s {...}.[/color]

                        Correct.
                        [color=blue]
                        > Incomplete types apply only to curly bracket things like
                        > enums, unions, and structs iirc.[/color]

                        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.ne t

                        Comment

                        • pete

                          #13
                          Re: mutually referential (Pg 140 K&amp;R2)

                          Dave Thompson wrote:[color=blue]
                          >
                          > On Sat, 23 Apr 2005 15:23:02 +1000, Russell Shaw
                          > <rjshawN_o@s_pa m.netspace.net. au> wrote:
                          > <snip>[color=green]
                          > > struct s *p declares p using an incomplete struct s type, which is later completed
                          > > with struct s {...}.[/color]
                          >
                          > Correct.
                          >[color=green]
                          > > Incomplete types apply only to curly bracket things like
                          > > enums, unions, and structs iirc.[/color]
                          >
                          > 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.[/color]

                          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

                          Comment

                          • Keith Thompson

                            #14
                            Re: mutually referential (Pg 140 K&amp;R2)

                            pete <pfiland@mindsp ring.com> writes:[color=blue]
                            > Dave Thompson wrote:[/color]
                            [...][color=blue][color=green]
                            >> 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.[/color]
                            >
                            > 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 */[/color]

                            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_Keit h) kst-u@mib.org <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.

                            Comment

                            • pete

                              #15
                              Re: mutually referential (Pg 140 K&amp;R2)

                              Keith Thompson wrote:[color=blue]
                              >
                              > pete <pfiland@mindsp ring.com> writes:[color=green]
                              > > Dave Thompson wrote:[/color]
                              > [...][color=green][color=darkred]
                              > >> 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.[/color]
                              > >
                              > > 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 */[/color]
                              >
                              > 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>[/color]

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

                              --
                              pete

                              Comment

                              Working...