p124 K&R

Discussion in 'C Programming' started by mdh, Aug 3, 2008.

  1. mdh

    mdh Guest

    Hi All,
    I have a couple of questions regarding the discussions on page 124 of
    k&r.

    1)

    This references functions working with complicated declarations in C.

    before main(...,...){}, (in file main.c), an enum is defined thus.

    enum {NAME, PARENS, BRACKETS};

    int gettoken(){......}


    refers to this with a return line thus.

    return tokentype = PARENS;

    Now, I am assuming that gettoken and main are compiled in the same
    file?

    I am trying to compile "gettoken" in my "foo.c" file. Hence I wish to
    ref the enum from there.

    I have tried this.

    Giving the enum an identifier,

    "enum syntax {NAME, PARENS, BRACKETS};"

    and then declaring it in foo.c thus.

    extern enum syntax; but this gives a warning "useless storage class
    specifier in empty declaration "



    2) staying with the "extern" theme.

    A char array is defined in main.c

    " char token[10]; "



    Again referenced from foo.c using syntax "extern char token".

    This in of itself does not give a warning, ( which I think is
    expected) but this line does.

    char *p = token " initialization makes pointer from integer without a
    cast"

    I would have thought that 'token' is changed to a ptr to char of the
    first element in the array, so not quite sure what or if to try and
    correct this.

    Thanks in advance....and holding my head...there have been some testy
    responses lately...so hopefully I do not fit those stereoptypes!!
    mdh, Aug 3, 2008
    #1
    1. Advertising

  2. mdh

    mdh Guest

    On Aug 3, 3:44 pm, mdh <> wrote:
    > Hi All,
    > I have a couple of questions regarding the discussions  on page 124 of
    > k&r.
    >
    > 1)
    >
    > This references functions working with complicated declarations in C.
    >
    > before  main(...,...){},  (in file main.c), an enum is defined thus.
    >
    > enum {NAME, PARENS, BRACKETS};
    >
    > int gettoken(){......}
    >
    > refers to this with a return line thus.
    >
    > return  tokentype = PARENS;
    >
    > Now, I am assuming that gettoken and main are compiled in the same
    > file?
    >
    > I am trying to compile "gettoken" in my "foo.c" file. Hence I wish to
    > ref the enum from there.
    >
    > I have tried this.
    >
    > Giving the enum an identifier,
    >
    >  "enum syntax {NAME, PARENS, BRACKETS};"
    >
    > and then declaring it in foo.c thus.
    >
    > extern enum syntax;  but this gives a warning  "useless storage class
    > specifier in empty declaration "



    Please ignore Q2...figured it out.
    >
    >
    > Thanks in advance....and holding my head...there have been some testy
    > responses lately...so hopefully I do not fit those stereoptypes!!
    mdh, Aug 4, 2008
    #2
    1. Advertising

  3. On Sun, 3 Aug 2008 15:44:02 -0700 (PDT), mdh <> wrote:

    >Hi All,
    >I have a couple of questions regarding the discussions on page 124 of
    >k&r.
    >
    >1)
    >
    >This references functions working with complicated declarations in C.
    >
    >before main(...,...){}, (in file main.c), an enum is defined thus.
    >
    >enum {NAME, PARENS, BRACKETS};
    >
    >int gettoken(){......}
    >
    >
    >refers to this with a return line thus.
    >
    >return tokentype = PARENS;
    >
    >Now, I am assuming that gettoken and main are compiled in the same
    >file?


    As shown on pages 124 and 125, they must be.

    >
    >I am trying to compile "gettoken" in my "foo.c" file. Hence I wish to
    >ref the enum from there.


    In addition to the enum, you also need token, tokentype, string.h, and
    ctype.h.

    >
    >I have tried this.
    >
    >Giving the enum an identifier,
    >
    > "enum syntax {NAME, PARENS, BRACKETS};"
    >
    >and then declaring it in foo.c thus.
    >
    >extern enum syntax; but this gives a warning "useless storage class
    >specifier in empty declaration "


    Even if this did not generate a diagnostic, while compiling foo.c what
    would the compiler know about enum syntax? How would it know that
    NAME was a synonym for 0, PARENS for 1, etc?

    >
    >
    >
    >2) staying with the "extern" theme.
    >
    >A char array is defined in main.c
    >
    >" char token[10]; "
    >
    >
    >
    >Again referenced from foo.c using syntax "extern char token".
    >
    >This in of itself does not give a warning, ( which I think is
    >expected) but this line does.
    >
    >char *p = token " initialization makes pointer from integer without a
    >cast"
    >
    >I would have thought that 'token' is changed to a ptr to char of the
    >first element in the array, so not quite sure what or if to try and
    >correct this.


    Your extern declaration did not say token was an array. It said token
    was a char. If you had coded
    extern char token[];
    your initialization of p would have worked.

    >
    >Thanks in advance....and holding my head...there have been some testy
    >responses lately...so hopefully I do not fit those stereoptypes!!


    If you want to split the main and gettoken functions into different
    source files (technically translation units), you have to insure that
    every file scope declaration in main.c is visible in foo.c AND that
    every file scope object in main.c is declared as extern in foo.c.

    One way to do this is copy all the lines on page 124 from
    #include <stdio.h>
    through
    int gettoken(void);
    from main.c to foo.c. Then copy the lines from
    int tokentype;
    through
    char out[1000];
    and insert the storage class "extern" in front of each.

    I don't like this because 1) any change in main.c must be duplicated
    in foo.c and 2) the compiler cannot check it the two are consistent.

    My preferred approach is MOVE the lines from
    #include <stdio.h>
    through
    int gettoken(void);
    to foo.h. Then COPY the lines from
    int tokentype;
    through
    char out[1000];
    and insert the storage class "extern" in front of each. Add
    #include "foo.h"
    to the front of both main.c and foo.c. Changes to the various
    declarations need only appear in foo.h. During the compilation of
    main.c, any inconsistencies between foo.h and the file scope objects
    defined in main will be flagged.

    --
    Remove del for email
    Barry Schwarz, Aug 4, 2008
    #3
  4. mdh

    mdh Guest

    On Aug 3, 6:30 pm, Barry Schwarz <> wrote:
    >
    > >This references functions working with complicated declarations in C.

    >
    > >before  main



    > >enum {NAME, PARENS, BRACKETS};

    >
    >
    >
    > >I am trying to compile "gettoken" in my "foo.c" file. Hence I wish to
    > >ref the enum from there.

    >
    > In addition to the enum, you also need token, tokentype, string.h, and
    > ctype.h.
    >


    In reality, my "foo.c" and "foo.h" contain all the little functions I
    have written as I have moved through k&r. This has helped me in
    understanding C. ( So I have str_cmp, str_len etc etc and if I need a
    new one, I have written it)...but, perhaps the time has come to move
    on and use those libraries.


    >
    >
    > >I have tried this.

    >
    > >Giving the enum an identifier,

    >
    > > "enum syntax {NAME, PARENS, BRACKETS};"

    >
    > >

    >
    > Even if this did not generate a diagnostic, while compiling foo.c what
    > would the compiler know about enum syntax?  How would it know that
    > NAME was a synonym for 0, PARENS for 1, etc?



    Well, that is what I find a little confusing. On p 124, k&r use the
    syntax "enum { NAME....etc}; without anything between the "enum" and
    the "{".From the appendix I think this is legal...in fact, if it is in
    K&R I assume it is legal. And like you, I also asked how foo.c could
    thus know about it in main.c, hence I added a "name" (perhaps syntax
    was a poor choice for a name)


    .
    >
    > >A char array is defined in main.c

    >
    > >" char token[10]; "


    >
    > >char *p = token " initialization makes pointer from integer without a
    > >cast"

    >
    >
    >
    > Your extern declaration did not say token was an array.  It said token
    > was a char.  If you had coded
    >         extern char token[];
    > your initialization of p would have worked.



    Point taken...
    >
    >
    >
    >
    > If you want to split the main and gettoken functions into different
    > source files (technically translation units), you have to insure that
    > every file scope declaration in main.c is visible in foo.c AND that
    > every file scope object in main.c is declared as extern in foo.c.
    >
    > One way...........



    > I don't like this because 1) any change in main.c must be duplicated
    > in foo.c and 2) the compiler cannot check it the two are consistent.


    If you don't like it, neither will I!!

    >
    > My preferred approach is MOVE the lines from
    >         #include <stdio.h>
    > through
    >         int gettoken(void);



    OK...so this includes " enum {NAME, ......};



    > to foo.h.  Then COPY the lines from
    >         int tokentype;
    > through
    >         char out[1000];
    > and insert the storage class "extern" in front of each.  Add
    >         #include "foo.h"
    > to the front of both main.c and foo.c.  Changes to the various
    > declarations need only appear in foo.h.  During the compilation of
    > main.c, any inconsistencies between foo.h and the file scope objects
    > defined in main will be flagged.


    Barry...I actually think to a large extent I have been doing this all
    along. But I could be wrong. I have all my definitions in foo.c, all
    my declarations in foo.h ( include foo.h in foo.c) and include foo.h
    in main.c The part that is new to me is the use of extern, but I
    think I have am getting the hang of it.
    One question though. If one includes enum {NAME...} in foo.h, is this
    not a definition. I was under the impression, that definitions should
    not be included in .h files. ( I guess the same question would apply
    to #define MAXTOKEN 100.} Or are these simple pre-processor macros?
    Sorry if I have misunderstood your answer and you have already
    answered this.
    Thanks
    mdh, Aug 4, 2008
    #4
  5. On Sun, 3 Aug 2008 19:25:26 -0700 (PDT), mdh <> wrote:

    >On Aug 3, 6:30 pm, Barry Schwarz <> wrote:

    snip

    >> My preferred approach is MOVE the lines from
    >>         #include <stdio.h>
    >> through
    >>         int gettoken(void);

    >
    >
    >OK...so this includes " enum {NAME, ......};
    >
    >
    >
    >> to foo.h.  Then COPY the lines from
    >>         int tokentype;
    >> through
    >>         char out[1000];
    >> and insert the storage class "extern" in front of each.  Add
    >>         #include "foo.h"
    >> to the front of both main.c and foo.c.  Changes to the various
    >> declarations need only appear in foo.h.  During the compilation of
    >> main.c, any inconsistencies between foo.h and the file scope objects
    >> defined in main will be flagged.

    >
    >Barry...I actually think to a large extent I have been doing this all
    >along. But I could be wrong. I have all my definitions in foo.c, all
    >my declarations in foo.h ( include foo.h in foo.c) and include foo.h
    >in main.c The part that is new to me is the use of extern, but I
    >think I have am getting the hang of it.
    >One question though. If one includes enum {NAME...} in foo.h, is this
    >not a definition. I was under the impression, that definitions should
    >not be included in .h files. ( I guess the same question would apply
    >to #define MAXTOKEN 100.} Or are these simple pre-processor macros?
    >Sorry if I have misunderstood your answer and you have already
    >answered this.


    In order for the enum declaration to define an object, you would have
    to name the object as part of the declaration. Something along the
    lines of
    enum {...} x;
    would define the object (variable) x of the enum type. The actual
    type would be an implementation specific type of integer.

    This is almost identical to the difference between the declaration
    struct tag {...};
    and the definition
    struct tag {...} y;
    The first declares the structure type and tells the compiler
    everything it needs to know about that type and its members. The
    second does all this plus defines an (aggregate) object of that type.

    So your impression is correct. Only declarations (and macro
    definitions) should be in header files. Your (actually K&R's)
    original enum statement did not define an object and so is in keeping
    with this general rule. If you look in 6.7.2.2-3, the standard
    clearly states that the identifiers in the enumerator list (NAME, etc)
    are declared (not defined) as constants of type int. The net effect
    is almost identical to a sequence of macro definitions
    #define NAME 0
    #define PARENS 1
    etc.
    and no one thinks twice about including those multiple source files.

    --
    Remove del for email
    Barry Schwarz, Aug 4, 2008
    #5
  6. mdh

    mdh Guest

    On Aug 3, 10:56 pm, Barry Schwarz <> wrote:
    > On Sun, 3 Aug 2008 19:25:26 -0700 (PDT), mdh <> wrote:




    > >On Aug 3, 6:30 pm, Barry Schwarz <> wrote:

    > In order for the enum declaration to define an object, you would have
    > to name the object as part of the declaration.  Something along the
    > lines of
    >     enum {...} x;
    > would define the object (variable) x of the enum type.  ....


    ...snip...


    >Your (actually K&R's)
    > original enum statement did not define an object and so is in keeping
    > with this general rule.


    So is it fair to say one can use enums in 2 general ways.

    One...without an (enum) identifier in which case the list identifiers
    are used as a substitute for simple #define statements.
    Two...with an identifier, in which case one can declare a variable of
    type "enum myenum" and assign to that variable one of the list
    constants ?

    In either case, if I wish to used that enum in another file ( ?
    translation unit) I need to **declare** it either in the header or
    before using it in that **other** function.


    thanks in advance.
    mdh, Aug 5, 2008
    #6
  7. On Tue, 5 Aug 2008 05:53:57 -0700 (PDT), mdh <> wrote:

    >On Aug 3, 10:56 pm, Barry Schwarz <> wrote:
    >> On Sun, 3 Aug 2008 19:25:26 -0700 (PDT), mdh <> wrote:

    >
    >
    >
    >> >On Aug 3, 6:30 pm, Barry Schwarz <> wrote:

    >> In order for the enum declaration to define an object, you would have
    >> to name the object as part of the declaration.  Something along the
    >> lines of
    >>     enum {...} x;
    >> would define the object (variable) x of the enum type.  ....

    >
    >...snip...
    >
    >
    >>Your (actually K&R's)
    >> original enum statement did not define an object and so is in keeping
    >> with this general rule.

    >
    >So is it fair to say one can use enums in 2 general ways.
    >
    >One...without an (enum) identifier in which case the list identifiers
    >are used as a substitute for simple #define statements.


    I think this is true but I don't know if it is complete. What I mean
    is that the enumerators appear to act the same as simple macro names
    but I don't know if there are any other aspects. For example, if you
    view an object of enum type in the debugger, do you see the integer
    value or the name or the enumerator? With a macro the answer is
    obviously the integer value but with an enumerator?

    >Two...with an identifier, in which case one can declare a variable of
    >type "enum myenum" and assign to that variable one of the list
    >constants ?
    >
    >In either case, if I wish to used that enum in another file ( ?
    >translation unit) I need to **declare** it either in the header or
    >before using it in that **other** function.


    Just like a macro name.

    --
    Remove del for email
    Barry Schwarz, Aug 5, 2008
    #7
  8. mdh

    Flash Gordon Guest

    Barry Schwarz wrote, On 05/08/08 18:23:
    > On Tue, 5 Aug 2008 05:53:57 -0700 (PDT), mdh <> wrote:
    >
    >> On Aug 3, 10:56 pm, Barry Schwarz <> wrote:
    >>> On Sun, 3 Aug 2008 19:25:26 -0700 (PDT), mdh <> wrote:

    >>
    >>
    >>>> On Aug 3, 6:30 pm, Barry Schwarz <> wrote:
    >>> In order for the enum declaration to define an object, you would have
    >>> to name the object as part of the declaration. Something along the
    >>> lines of
    >>> enum {...} x;
    >>> would define the object (variable) x of the enum type. ....

    >> ...snip...
    >>
    >>
    >>> Your (actually K&R's)
    >>> original enum statement did not define an object and so is in keeping
    >>> with this general rule.

    >> So is it fair to say one can use enums in 2 general ways.
    >>
    >> One...without an (enum) identifier in which case the list identifiers
    >> are used as a substitute for simple #define statements.

    >
    > I think this is true but I don't know if it is complete. What I mean
    > is that the enumerators appear to act the same as simple macro names
    > but I don't know if there are any other aspects. For example, if you
    > view an object of enum type in the debugger, do you see the integer
    > value or the name or the enumerator? With a macro the answer is
    > obviously the integer value but with an enumerator?


    That all depends on the debugger. Some debuggers even know about macros
    these days!

    Another advantage of using an enum is that the identifiers then follow
    "normal" C scoping unlike macros. Comnsider the following...

    int foo() {
    #define BUFSIZ 50
    unsigned char buf[BUFSIZ];
    ....

    int bar() {
    enum { BUFSIZ=50 };
    unsigned char buf[BUFSIZ];
    ....


    >> Two...with an identifier, in which case one can declare a variable of
    >> type "enum myenum" and assign to that variable one of the list
    >> constants ?
    >>
    >> In either case, if I wish to used that enum in another file ( ?
    >> translation unit) I need to **declare** it either in the header or
    >> before using it in that **other** function.

    >
    > Just like a macro name.


    Indeed. Also like a typedef or struct definition.
    --
    Flash Gordon
    Flash Gordon, Aug 5, 2008
    #8
  9. mdh

    mdh Guest

    On Aug 5, 10:23 am, Barry Schwarz <> wrote:
    > On Tue, 5 Aug 2008 05:53:57 -0700 (PDT), mdh <> wrote:
    >
    > >So is it fair to say one can use enums in 2 general ways.

    >
    > >

    >
    > I think this is true but I don't know if it is complete.
    >
    > >Two...with an identifier,....


    ......snip

    ....
    >
    > > I need to **declare** it either in the header or
    > >before using it in that **other** function.

    >
    > Just like a macro name.
    >


    Thank you for that. I think section 6 ( K&R) will give me a little
    more insight into enumerators. For some reason, K&R go into very
    little detail about this ( other than describing how to define it) ,
    and the only example I saw where it is used with an identifier was in
    one of the exercises (2.2) in which T&G use that technique to write a
    solution. So your explanation has been very helpful.
    mdh, Aug 6, 2008
    #9
  10. mdh

    mdh Guest

    On Aug 5, 12:18 pm, Flash Gordon <> wrote:
    > Barry Schwarz wrote, On 05/08/08 18:23:
    >
    >
    > >> Two...with an identifier, in which case one can declare a variable of
    > >> type "enum myenum" and assign to that variable one of the list
    > >> constants ?

    >
    > >> In either case, if I wish to used that enum in another file ( ?
    > >> translation unit) I need to **declare** it either in the header or
    > >> before using it in that **other** function.

    >
    > > Just like a macro name.

    >
    > Indeed. Also like a typedef or struct definition.
    > --


    Those are next on the list! Thank you.
    mdh, Aug 6, 2008
    #10
  11. On Tue, 05 Aug 2008 20:18:52 +0100, Flash Gordon
    <> wrote:

    >Barry Schwarz wrote, On 05/08/08 18:23:
    >> On Tue, 5 Aug 2008 05:53:57 -0700 (PDT), mdh <> wrote:
    >>
    >>> On Aug 3, 10:56 pm, Barry Schwarz <> wrote:
    >>>> On Sun, 3 Aug 2008 19:25:26 -0700 (PDT), mdh <> wrote:
    >>>
    >>>
    >>>>> On Aug 3, 6:30 pm, Barry Schwarz <> wrote:
    >>>> In order for the enum declaration to define an object, you would have
    >>>> to name the object as part of the declaration. Something along the
    >>>> lines of
    >>>> enum {...} x;
    >>>> would define the object (variable) x of the enum type. ....
    >>> ...snip...
    >>>
    >>>
    >>>> Your (actually K&R's)
    >>>> original enum statement did not define an object and so is in keeping
    >>>> with this general rule.
    >>> So is it fair to say one can use enums in 2 general ways.
    >>>
    >>> One...without an (enum) identifier in which case the list identifiers
    >>> are used as a substitute for simple #define statements.

    >>
    >> I think this is true but I don't know if it is complete. What I mean
    >> is that the enumerators appear to act the same as simple macro names
    >> but I don't know if there are any other aspects. For example, if you
    >> view an object of enum type in the debugger, do you see the integer
    >> value or the name or the enumerator? With a macro the answer is
    >> obviously the integer value but with an enumerator?

    >
    >That all depends on the debugger. Some debuggers even know about macros
    >these days!
    >
    >Another advantage of using an enum is that the identifiers then follow
    >"normal" C scoping unlike macros. Comnsider the following...
    >
    >int foo() {
    >#define BUFSIZ 50
    > unsigned char buf[BUFSIZ];
    >...
    >
    >int bar() {
    > enum { BUFSIZ=50 };
    > unsigned char buf[BUFSIZ];


    Thank you. I knew there had to be a non-trivial distinction but I
    couldn't think of what it might be.

    >...
    >
    >
    >>> Two...with an identifier, in which case one can declare a variable of
    >>> type "enum myenum" and assign to that variable one of the list
    >>> constants ?
    >>>
    >>> In either case, if I wish to used that enum in another file ( ?
    >>> translation unit) I need to **declare** it either in the header or
    >>> before using it in that **other** function.

    >>
    >> Just like a macro name.

    >
    >Indeed. Also like a typedef or struct definition.


    --
    Remove del for email
    Barry Schwarz, Aug 6, 2008
    #11
    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.

Share This Page