Re: C scope and struct definitions

Discussion in 'C Programming' started by Eric Sosman, Jun 22, 2012.

  1. Eric Sosman

    Eric Sosman Guest

    On 6/22/2012 1:30 PM, Kenneth Brody wrote:
    > The discussion about scope in the "What a stupid gcc" thread reminded me
    > of the one time (that I recall) where I was bitten by this. I don't
    > recall the specifics, but it had to do with a function that was passed a
    > pointer to a struct, when there was no struct by that name visible.
    >
    > Something like:
    >
    > int foo(struct bar *);
    >
    > ...
    >
    > int foo(struct bar *baz)
    > {
    > ...
    > }
    >
    > The compiler decided that the "struct bar" in one place was not the same
    > "struct bar" in the other place.
    >
    > The solution, of course, was to add a simple "struct bar;" at file scope
    > prior to its first reference.
    >
    > I can't duplicate any error right now, though a simple test does give me
    > a warning:
    >
    > 'bar' : named type definition in parentheses
    >
    > Was the compiler correct to treat the two references as distinct? If a
    > struct definition is not visible at the time, can a reference to a
    > pointer to that struct be a different type than another one to the same
    > named struct?
    >
    > Again, I don't remember the exact details, as it was some time ago.


    The compiler was right. The relevant text is in 6.2.1p4:

    "[...] If the declarator or type specifier that declares
    the identifier appears inside a block or within the list
    of parameter declarations in a function definition, the
    identifier has block scope, which terminates at the end
    of the associated block. If the declarator or type specifier
    that declares the identifier appears within the list of
    parameter declarations in a function prototype (not part
    of a function definition), the identifier has function
    prototype scope, which terminates at the end of the
    function declarator. [...]"

    So: The scope of `struct bar' in the first part of your example
    ends where the prototype does (second sentence), while that of
    `struct bar' in the second part is confined to the function body
    (first sentence). The scopes do not overlap, so the two uses of
    `struct bar' are distinct.

    See also FAQ Question 11.5.

    --
    Eric Sosman
    d
     
    Eric Sosman, Jun 22, 2012
    #1
    1. Advertising

  2. Eric Sosman

    Alan Curry Guest

    In article <js2buv$evv$>,
    Eric Sosman <> wrote:
    >On 6/22/2012 1:30 PM, Kenneth Brody wrote:
    >>
    >> int foo(struct bar *);
    >>
    >> ...
    >>
    >> int foo(struct bar *baz)
    >> {
    >> ...
    >> }
    >>
    >> The compiler decided that the "struct bar" in one place was not the same
    >> "struct bar" in the other place.

    [...]
    >
    > The compiler was right. The relevant text is in 6.2.1p4:


    But is the compiler right for a real reason, or is it just a continuation of
    a historical accident? Why would you ever want this behavior?

    I don't even see why you'd ever want any scope for a struct type other than
    "from here to the end of the file". Types are global things.

    --
    Alan Curry
     
    Alan Curry, Jun 22, 2012
    #2
    1. Advertising

  3. Eric Sosman

    Ben Pfaff Guest

    (Alan Curry) writes:

    > I don't even see why you'd ever want any scope for a struct type other than
    > "from here to the end of the file". Types are global things.


    Occasionally I do declare and use a struct type within a
    function. I'd like that to continue working.

    I do agree that the behavior of struct types defined within a
    function prototype is surprising and not useful.
     
    Ben Pfaff, Jun 22, 2012
    #3
  4. Eric Sosman

    Eric Sosman Guest

    On 6/22/2012 6:40 PM, Alan Curry wrote:
    > In article <js2buv$evv$>,
    > Eric Sosman <> wrote:
    >> On 6/22/2012 1:30 PM, Kenneth Brody wrote:
    >>>
    >>> int foo(struct bar *);
    >>>
    >>> ...
    >>>
    >>> int foo(struct bar *baz)
    >>> {
    >>> ...
    >>> }
    >>>
    >>> The compiler decided that the "struct bar" in one place was not the same
    >>> "struct bar" in the other place.

    > [...]
    >>
    >> The compiler was right. The relevant text is in 6.2.1p4:

    >
    > But is the compiler right for a real reason, or is it just a continuation of
    > a historical accident? Why would you ever want this behavior?


    The Rationale sheds no light my tired old eyes can see. You
    are welcome to read it for yourself. (Also, if you think the
    normative text of the formal definition of the C language does not
    qualify as "a real reason," well ...)

    > I don't even see why you'd ever want any scope for a struct type other than
    > "from here to the end of the file". Types are global things.


    Say, what?

    void f(void) {
    static const struct foo {
    const char *roman;
    int decimal;
    } table[] = { { "I", 1 }, { "II", 2 }, ... };
    ...
    }

    void g(void) {
    struct foo {
    double payload;
    struct foo *next;
    } *head, *p, *q;
    ...
    }

    Do you seriously maintain that these two `struct foo' types
    should conflict with each other? If so, why? Explain why you
    feel it is Wrong for a function to declare and use its own
    private type for its own purposes, and why f() should have to
    worry about what g() does in the privacy of its own block.

    --
    Eric Sosman
    d
     
    Eric Sosman, Jun 23, 2012
    #4
  5. Eric Sosman

    Alan Curry Guest

    In article <js32rk$siv$>,
    Eric Sosman <> wrote:
    >On 6/22/2012 6:40 PM, Alan Curry wrote:
    >>
    >> But is the compiler right for a real reason, or is it just a continuation of
    >> a historical accident? Why would you ever want this behavior?

    >
    > The Rationale sheds no light my tired old eyes can see. You
    >are welcome to read it for yourself. (Also, if you think the
    >normative text of the formal definition of the C language does not
    >qualify as "a real reason," well ...)


    The standard was supposed to codify existing practice. A real reason would
    have to come from before standardization. Was there a real reason for the
    existence of such a small, useless scope?

    >
    >> I don't even see why you'd ever want any scope for a struct type other than
    >> "from here to the end of the file". Types are global things.

    >
    > Say, what?
    >
    > void f(void) {
    > static const struct foo {
    > const char *roman;
    > int decimal;
    > } table[] = { { "I", 1 }, { "II", 2 }, ... };
    > ...
    > }
    >
    > void g(void) {
    > struct foo {
    > double payload;
    > struct foo *next;
    > } *head, *p, *q;
    > ...
    > }
    >
    >Do you seriously maintain that these two `struct foo' types
    >should conflict with each other? If so, why? Explain why you
    >feel it is Wrong for a function to declare and use its own
    >private type for its own purposes, and why f() should have to
    >worry about what g() does in the privacy of its own block.


    I don't think we'd be losing anything if those declarations were simply
    illegal. Declare your structs before your functions. They aren't variables.

    A struct describes the procedure for interpreting bits in memory. As a
    procedure description, it's more like a function than a variable. It doesn't
    occupy memory itself, so it doesn't have a lifetime that can end when the
    function call ends. Putting it inside the function gives you nothing.

    If you really have two different structs with the same name in one program,
    you should want to be warned about it. It's a sign that you should either
    merge them (if they are different representations of the same concept) or
    rename them.

    Variables, functions, and constant data are all defined with reference to
    types. Types are the most fundamental entities in a program. They deserve
    globally unique names.

    --
    Alan Curry
     
    Alan Curry, Jun 23, 2012
    #5
  6. (Alan Curry) writes:
    > In article <js32rk$siv$>,
    > Eric Sosman <> wrote:
    >>On 6/22/2012 6:40 PM, Alan Curry wrote:
    >>>
    >>> But is the compiler right for a real reason, or is it just a
    >>> continuation of a historical accident? Why would you ever want this
    >>> behavior?

    >>
    >> The Rationale sheds no light my tired old eyes can see. You
    >>are welcome to read it for yourself. (Also, if you think the
    >>normative text of the formal definition of the C language does not
    >>qualify as "a real reason," well ...)

    >
    > The standard was supposed to codify existing practice. A real reason
    > would have to come from before standardization. Was there a real
    > reason for the existence of such a small, useless scope?


    Yes: it's not useless.

    >>
    >>> I don't even see why you'd ever want any scope for a struct type other than
    >>> "from here to the end of the file". Types are global things.

    >>
    >> Say, what?
    >>
    >> void f(void) {
    >> static const struct foo {
    >> const char *roman;
    >> int decimal;
    >> } table[] = { { "I", 1 }, { "II", 2 }, ... };
    >> ...
    >> }
    >>
    >> void g(void) {
    >> struct foo {
    >> double payload;
    >> struct foo *next;
    >> } *head, *p, *q;
    >> ...
    >> }
    >>
    >>Do you seriously maintain that these two `struct foo' types
    >>should conflict with each other? If so, why? Explain why you
    >>feel it is Wrong for a function to declare and use its own
    >>private type for its own purposes, and why f() should have to
    >>worry about what g() does in the privacy of its own block.

    >
    > I don't think we'd be losing anything if those declarations were simply
    > illegal. Declare your structs before your functions. They aren't variables.


    We'd lose backward compatibility; it would break existing code. I've
    seen plenty of small programs that define types inside main (or
    would you make main a special case?).

    Nothing stops you from declaring your structs at file scope if you
    want to, and I agree that it's *usually* the best thing to do.

    But if a given type happens to be used only inside one function,
    or even inside one block, the language allows you to declare it
    there without polluting the rest of the program's namespace.

    > A struct describes the procedure for interpreting bits in memory. As a
    > procedure description, it's more like a function than a variable. It doesn't
    > occupy memory itself, so it doesn't have a lifetime that can end when the
    > function call ends. Putting it inside the function gives you nothing.


    We're talking about scope, not lifetime. Types don't have lifetime,
    but like any other declared entity, they do have scope (the region
    of source code over in they're visible).

    The scope rules for types are consistent with the scope rules for
    objects. This consistency makes the language simpler, and has no
    real cost that I can see. Again, if you don't want to declare types
    at block scope, then by all means don't.

    [...]

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jun 24, 2012
    #6
  7. Eric Sosman

    Eric Sosman Guest

    On 6/23/2012 6:06 PM, Alan Curry wrote:
    > In article <js32rk$siv$>,
    > Eric Sosman <> wrote:
    >> On 6/22/2012 6:40 PM, Alan Curry wrote:
    >>>
    >>> But is the compiler right for a real reason, or is it just a continuation of
    >>> a historical accident? Why would you ever want this behavior?

    >>
    >> The Rationale sheds no light my tired old eyes can see. You
    >> are welcome to read it for yourself. (Also, if you think the
    >> normative text of the formal definition of the C language does not
    >> qualify as "a real reason," well ...)

    >
    > The standard was supposed to codify existing practice. A real reason would
    > have to come from before standardization. Was there a real reason for the
    > existence of such a small, useless scope?


    Note that existing practice had no notion of prototypes at all,
    so the issue of "prototype scope" simply didn't exist. (The ANSI
    Standard invented other things new to the language, too: `void',
    for example.)

    But once you've decided to declare a function with a prototype,
    what scope should any identifiers in the prototype have? It seems
    pretty clear you don't want them leaking outside, else

    void foo(char *p);
    void bar(double *p);

    .... wouldn't compile, because of the conflicting declarations of `p'.
    I suggest that would have been untenable.

    A consequence of "What happens in prototype stays in prototype"
    is that *all* in-prototype identifiers' scopes are limited to the
    prototype itself. Yes, it leads to a useless construct -- but have
    you got a usable alternative?

    >>
    >>> I don't even see why you'd ever want any scope for a struct type other than
    >>> "from here to the end of the file". Types are global things.

    >>
    >> Say, what?
    >>
    >> void f(void) {
    >> static const struct foo {
    >> const char *roman;
    >> int decimal;
    >> } table[] = { { "I", 1 }, { "II", 2 }, ... };
    >> ...
    >> }
    >>
    >> void g(void) {
    >> struct foo {
    >> double payload;
    >> struct foo *next;
    >> } *head, *p, *q;
    >> ...
    >> }
    >>
    >> Do you seriously maintain that these two `struct foo' types
    >> should conflict with each other? If so, why? Explain why you
    >> feel it is Wrong for a function to declare and use its own
    >> private type for its own purposes, and why f() should have to
    >> worry about what g() does in the privacy of its own block.

    >
    > I don't think we'd be losing anything if those declarations were simply
    > illegal. Declare your structs before your functions. They aren't variables.


    I'm glad the Standard didn't take your view. While I'll admit
    that function-specific types are not all that common, I'll maintain
    that they are extremely useful. Most often, there's an ad-hoc
    table of some kind to assist a function in the performance of its
    work: Maybe an association of states with their capitols, or ranges
    of `x' where a rational function/Chebyshev approximation/continued
    fraction is the preferred computation method. Whatever it is, if
    it's specific to the operation of one function I see *no* reason to
    inflict it on others.

    > A struct describes the procedure for interpreting bits in memory. As a
    > procedure description, it's more like a function than a variable. It doesn't
    > occupy memory itself, so it doesn't have a lifetime that can end when the
    > function call ends. Putting it inside the function gives you nothing.


    All the same statements could be made about an identifier of any
    kind whatsoever. Should `x' leak out of one function into others?

    > If you really have two different structs with the same name in one program,
    > you should want to be warned about it. It's a sign that you should either
    > merge them (if they are different representations of the same concept) or
    > rename them.


    Bah.

    > Variables, functions, and constant data are all defined with reference to
    > types. Types are the most fundamental entities in a program. They deserve
    > globally unique names.


    I'm with you, up to the antepenultimate word. Why should a
    type declared in the bowels of some function in some library I don't
    even have source to be "global?" How shall I select my identifiers
    to ensure that no third party's library bollixes them?

    If you want "global," go back to BASICs. (By which I mean
    Kemeny and Kurtz, not MS.)

    --
    Eric Sosman
    d
     
    Eric Sosman, Jun 24, 2012
    #7
  8. Eric Sosman

    Alan Curry Guest

    In article <js5l0m$64l$>,
    Eric Sosman <> wrote:
    >On 6/23/2012 6:06 PM, Alan Curry wrote:
    >> In article <js32rk$siv$>,
    >> Eric Sosman <> wrote:
    >>> On 6/22/2012 6:40 PM, Alan Curry wrote:
    >>>>
    >>>> But is the compiler right for a real reason, or is it just a continuation of
    >>>> a historical accident? Why would you ever want this behavior?
    >>>
    >>> The Rationale sheds no light my tired old eyes can see. You
    >>> are welcome to read it for yourself. (Also, if you think the
    >>> normative text of the formal definition of the C language does not
    >>> qualify as "a real reason," well ...)

    >>
    >> The standard was supposed to codify existing practice. A real reason would
    >> have to come from before standardization. Was there a real reason for the
    >> existence of such a small, useless scope?

    >
    > Note that existing practice had no notion of prototypes at all,
    >so the issue of "prototype scope" simply didn't exist. (The ANSI
    >Standard invented other things new to the language, too: `void',
    >for example.)
    >
    > But once you've decided to declare a function with a prototype,
    >what scope should any identifiers in the prototype have? It seems
    >pretty clear you don't want them leaking outside, else
    >
    > void foo(char *p);
    > void bar(double *p);
    >
    >... wouldn't compile, because of the conflicting declarations of `p'.
    >I suggest that would have been untenable.


    Those names should simply be omitted, and it would be a good thing if they
    weren't allowed either. They serve no purpose and cause problems in header
    files when one header defines a macro that another header uses as an argument
    name in a prototype.

    We are allowed to use the intelligent comment markers /* */ in C, not just
    the dumb // to-end-of-line kind, so you can say

    void f(char * /*p*/, double * /*q*/);

    if the parameter names are meant to be documentation.

    Anyway, putting type names and variable names into a single category and
    calling them "identifiers" is a false generalization. It works at the
    technical level for the compiler implementor I guess, but besides that what's
    the reason for lumping them together and insisting that they behave the same?
    If you can't explain it without the word "identifier" then there is no
    reason, it's just a thought process that's being misled by a bit of escaped
    compiler-writer's jargon.

    >>
    >> I don't think we'd be losing anything if those declarations were simply
    >> illegal. Declare your structs before your functions. They aren't variables.

    >
    > I'm glad the Standard didn't take your view. While I'll admit
    >that function-specific types are not all that common, I'll maintain
    >that they are extremely useful. Most often, there's an ad-hoc
    >table of some kind to assist a function in the performance of its
    >work: Maybe an association of states with their capitols, or ranges
    >of `x' where a rational function/Chebyshev approximation/continued
    >fraction is the preferred computation method. Whatever it is, if
    >it's specific to the operation of one function I see *no* reason to
    >inflict it on others.


    The same could be said for a function that's only called by one other
    function. Should we have nested functions then?

    >
    >> A struct describes the procedure for interpreting bits in memory. As a
    >> procedure description, it's more like a function than a variable. It doesn't
    >> occupy memory itself, so it doesn't have a lifetime that can end when the
    >> function call ends. Putting it inside the function gives you nothing.

    >
    > All the same statements could be made about an identifier of any
    >kind whatsoever. Should `x' leak out of one function into others?


    Variable scopes make sense because the object named by the variable doesn't
    exist until the function is called. A type isn't an object.

    >> Variables, functions, and constant data are all defined with reference to
    >> types. Types are the most fundamental entities in a program. They deserve
    >> globally unique names.

    >
    > I'm with you, up to the antepenultimate word. Why should a
    >type declared in the bowels of some function in some library I don't
    >even have source to be "global?" How shall I select my identifiers
    >to ensure that no third party's library bollixes them?
    >
    > If you want "global," go back to BASICs. (By which I mean
    >Kemeny and Kurtz, not MS.)


    You don't have to take "global" that far. Third party libraries occupy
    separate globes. Uniqueness within a source file is a reasonable requirement.
    Uniqueness within a set of files that are compiled at the same time would be
    a good bonus check.

    --
    Alan Curry
     
    Alan Curry, Jun 24, 2012
    #8
  9. Eric Sosman

    James Kuyper Guest

    On 06/23/2012 07:54 PM, Eric Sosman wrote:
    ....
    > But once you've decided to declare a function with a prototype,
    > what scope should any identifiers in the prototype have? It seems
    > pretty clear you don't want them leaking outside, else
    >
    > void foo(char *p);
    > void bar(double *p);
    >
    > ... wouldn't compile, because of the conflicting declarations of `p'.
    > I suggest that would have been untenable.
    >
    > A consequence of "What happens in prototype stays in prototype"
    > is that *all* in-prototype identifiers' scopes are limited to the
    > prototype itself. Yes, it leads to a useless construct -- but have
    > you got a usable alternative?


    Two:
    C++ way: prohibit definition of types in there parameter list of a
    function declaration.

    Useful alternative: give types defined in a function's parameter list
    the same scope as the function's declaration, rather than function
    prototype scope.

    ....
    > I'm glad the Standard didn't take your view. While I'll admit
    > that function-specific types are not all that common, I'll maintain
    > that they are extremely useful. Most often, there's an ad-hoc
    > table of some kind to assist a function in the performance of its
    > work: Maybe an association of states with their capitols, or ranges
    > of `x' where a rational function/Chebyshev approximation/continued
    > fraction is the preferred computation method. Whatever it is, if
    > it's specific to the operation of one function I see *no* reason to
    > inflict it on others.


    Agreed; for things declared inside of a function, that's entirely
    reasonable. But for a type that's part of a function's interface, if the
    identifier for that type has a scope is limited to the function body, no
    other function can call it - which is rather limiting.

    >> A struct describes the procedure for interpreting bits in memory. As a
    >> procedure description, it's more like a function than a variable. It doesn't
    >> occupy memory itself, so it doesn't have a lifetime that can end when the
    >> function call ends. Putting it inside the function gives you nothing.

    >
    > All the same statements could be made about an identifier of any
    > kind whatsoever. Should `x' leak out of one function into others?


    No, only identifiers identifying types should leak out, only when they
    are part of the parameter list.
    --
    James Kuyper
     
    James Kuyper, Jun 24, 2012
    #9
  10. Eric Sosman

    Eric Sosman Guest

    On 6/23/2012 8:56 PM, Alan Curry wrote:
    > In article <js5l0m$64l$>,
    > Eric Sosman <> wrote:
    >> [...]
    >> But once you've decided to declare a function with a prototype,
    >> what scope should any identifiers in the prototype have? It seems
    >> pretty clear you don't want them leaking outside, else
    >>
    >> void foo(char *p);
    >> void bar(double *p);
    >>
    >> ... wouldn't compile, because of the conflicting declarations of `p'.
    >> I suggest that would have been untenable.

    >
    > Those names should simply be omitted, and it would be a good thing if they
    > weren't allowed either. They serve no purpose and cause problems in header
    > files when one header defines a macro that another header uses as an argument
    > name in a prototype.
    >
    > We are allowed to use the intelligent comment markers /* */ in C, not just
    > the dumb // to-end-of-line kind, so you can say
    >
    > void f(char * /*p*/, double * /*q*/);
    >
    > if the parameter names are meant to be documentation.


    So your argument against prototype scope boils down to "C's
    syntax should be different." Okay, fine; tastes differ. But two
    points stand out: First, that *given* the decision to allow
    identifiers in prototypes, prototype scope follows as a practical
    necessity. Second, that if identifiers were forbidden in prototypes,
    then the entire thread would never have started in the first place
    and so the whole argument evaporates.

    > Anyway, putting type names and variable names into a single category and
    > calling them "identifiers" is a false generalization.


    If type names are somehow segregated from names-of-other-things,
    does that mean

    double int = 42;
    long * double void(short long);
    struct struct { long *union; char enum; };

    .... are to your liking?

    (In my early youth I was weaned on a language that had no
    reserved words at all, a language in which `DO 10 I = (1 , 10)'
    was perfectly legal and *not* a loop construct. For a while I
    esteemed this as a sort of Purity. I got over it.)

    But, hey: Back to the beginning. You asked whether a compiler
    that obeyed 6.2.1p4 did so quote "for a real reason" end quote.
    The answer to your question is "Yes," because 6.2.1p4 dictates
    how the compiler must behave. Debate about whether 6.2.1p4 ought
    to have said something else should be between you and X3J11, not
    between you and me.

    --
    Eric Sosman
    d
     
    Eric Sosman, Jun 24, 2012
    #10
  11. Eric Sosman

    Eric Sosman Guest

    On 6/23/2012 8:57 PM, James Kuyper wrote:
    > On 06/23/2012 07:54 PM, Eric Sosman wrote:
    >> [...]
    >> A consequence of "What happens in prototype stays in prototype"
    >> is that *all* in-prototype identifiers' scopes are limited to the
    >> prototype itself. Yes, it leads to a useless construct -- but have
    >> you got a usable alternative?

    >
    > Two:
    > C++ way: prohibit definition of types in there parameter list of a
    > function declaration.


    I'm not a C++ lawyer (nor even a C++ fluent speaker (although I
    have "C++ Readability," go figure)), but "no type declarations in
    function declarations" seems awfully restrictive:

    int main(int argc, char **argv) // BZZZZT!

    What must one do instead?

    typedef char **charStarStar;
    int main(int argc, charStarStar argv)

    ? But, as I say, I don't speak That Other Language, and maybe I've
    read more into your synopsis than was actually present.

    > Useful alternative: give types defined in a function's parameter list
    > the same scope as the function's declaration, rather than function
    > prototype scope.


    I'd worked up a nice reductio ad absurdum, and then realized that
    you meant something other than what you'd said: You said "same scope
    as the function's *declaration*," but you meant "same scope as the
    function's *identifier*." I dunno: Might be reasonable, might have
    unwelcome consequences in corner cases, might disable some corner
    cases that are legitimate now but Ought To Be Banned (Just Think Of
    The Children!), ... Needs more thought than my graying gray cells
    can muster.

    --
    Eric Sosman
    d
     
    Eric Sosman, Jun 24, 2012
    #11
  12. (Alan Curry) writes:
    > In article <js5l0m$64l$>,
    > Eric Sosman <> wrote:
    >>On 6/23/2012 6:06 PM, Alan Curry wrote:
    >>> In article <js32rk$siv$>,
    >>> Eric Sosman <> wrote:
    >>>> On 6/22/2012 6:40 PM, Alan Curry wrote:
    >>>>> But is the compiler right for a real reason, or is it just a
    >>>>> continuation of a historical accident? Why would you ever want
    >>>>> this behavior?
    >>>>
    >>>> The Rationale sheds no light my tired old eyes can see. You
    >>>> are welcome to read it for yourself. (Also, if you think the
    >>>> normative text of the formal definition of the C language does not
    >>>> qualify as "a real reason," well ...)
    >>>
    >>> The standard was supposed to codify existing practice. A real reason
    >>> would have to come from before standardization. Was there a real
    >>> reason for the existence of such a small, useless scope?

    >>
    >> Note that existing practice had no notion of prototypes at all,
    >>so the issue of "prototype scope" simply didn't exist. (The ANSI
    >>Standard invented other things new to the language, too: `void',
    >>for example.)
    >>
    >> But once you've decided to declare a function with a prototype,
    >>what scope should any identifiers in the prototype have? It seems
    >>pretty clear you don't want them leaking outside, else
    >>
    >> void foo(char *p);
    >> void bar(double *p);
    >>
    >>... wouldn't compile, because of the conflicting declarations of `p'.
    >>I suggest that would have been untenable.

    >
    > Those names should simply be omitted, and it would be a good thing if they
    > weren't allowed either. They serve no purpose and cause problems in header
    > files when one header defines a macro that another header uses as an argument
    > name in a prototype.
    >
    > We are allowed to use the intelligent comment markers /* */ in C, not just
    > the dumb // to-end-of-line kind, so you can say
    >
    > void f(char * /*p*/, double * /*q*/);
    >
    > if the parameter names are meant to be documentation.


    Personally, I like having names for parameters in function declarations,
    though I'm not pleased that they're ignored. My own preference would be
    to make the names mandatory, and to require them to match the names used
    in the function's definition.

    So neither of is 100% satisfied with the way C is defined. I don't know
    of anyone who is.

    (I disagree with your characterization of // comments as "dumb", but I
    won't get into that.)

    > Anyway, putting type names and variable names into a single category and
    > calling them "identifiers" is a false generalization. It works at the
    > technical level for the compiler implementor I guess, but besides that what's
    > the reason for lumping them together and insisting that they behave the same?
    > If you can't explain it without the word "identifier" then there is no
    > reason, it's just a thought process that's being misled by a bit of escaped
    > compiler-writer's jargon.


    I'd say it's a perfectly valid generalization. They *are* both
    identifiers, and they follow the same scope rules.

    You advocate treating type names as a special case with different scope
    rules than other identifiers. That's a valid preference, but not one
    that I share -- and not one that's consistent with C as it's currently
    defined.

    >>> I don't think we'd be losing anything if those declarations were simply
    >>> illegal. Declare your structs before your functions. They aren't variables.

    >>
    >> I'm glad the Standard didn't take your view. While I'll admit
    >>that function-specific types are not all that common, I'll maintain
    >>that they are extremely useful. Most often, there's an ad-hoc
    >>table of some kind to assist a function in the performance of its
    >>work: Maybe an association of states with their capitols, or ranges
    >>of `x' where a rational function/Chebyshev approximation/continued
    >>fraction is the preferred computation method. Whatever it is, if
    >>it's specific to the operation of one function I see *no* reason to
    >>inflict it on others.

    >
    > The same could be said for a function that's only called by one other
    > function. Should we have nested functions then?


    Many languages do have nested functions. What tends to make them
    complicated is the need to define rules for accessing objects defined
    in an outer function. I wouldn't strongly object to adding nested
    functions to C (and gcc supports them as an extension), but I don't
    think they're all that important; we've gotten along without them
    for a very long time.

    [...]

    > Variable scopes make sense because the object named by the variable doesn't
    > exist until the function is called. A type isn't an object.


    Are you conflating scope and lifetime?

    [...]

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jun 24, 2012
    #12
  13. Eric Sosman

    James Kuyper Guest

    On 06/23/2012 10:11 PM, Eric Sosman wrote:
    > On 6/23/2012 8:57 PM, James Kuyper wrote:
    >> On 06/23/2012 07:54 PM, Eric Sosman wrote:
    >>> [...]
    >>> A consequence of "What happens in prototype stays in prototype"
    >>> is that *all* in-prototype identifiers' scopes are limited to the
    >>> prototype itself. Yes, it leads to a useless construct -- but have
    >>> you got a usable alternative?

    >>
    >> Two:
    >> C++ way: prohibit definition of types in there parameter list of a
    >> function declaration.

    >
    > I'm not a C++ lawyer (nor even a C++ fluent speaker (although I
    > have "C++ Readability," go figure)), but "no type declarations in
    > function declarations" seems awfully restrictive:
    >
    > int main(int argc, char **argv) // BZZZZT!


    I said "type definition", not type declaration. Neither int nor char**
    were defined in that declaration, they were only specified as the types
    of the corresponding parameters. They aren't identifiers, they don't
    have a scope associated with them. Types that have scoped identifiers
    that can be defined by user code include struct, union, and enum types.

    >> Useful alternative: give types defined in a function's parameter list
    >> the same scope as the function's declaration, rather than function
    >> prototype scope.

    >
    > I'd worked up a nice reductio ad absurdum, and then realized that
    > you meant something other than what you'd said: You said "same scope
    > as the function's *declaration*," but you meant "same scope as the
    > function's *identifier*." I dunno: Might be reasonable, might have
    > unwelcome consequences in corner cases, might disable some corner
    > cases that are legitimate now but Ought To Be Banned (Just Think Of
    > The Children!), ... Needs more thought than my graying gray cells
    > can muster.


    Yes, think on it. Function declarations that would be affected by this
    suggestion are useless, so I don't see how it could break existing
    working code. Other kinds of unwelcome consequences are certainly
    possible, of course.
    --
    James Kuyper
     
    James Kuyper, Jun 24, 2012
    #13
  14. Eric Sosman <> writes:
    > On 6/23/2012 8:57 PM, James Kuyper wrote:

    [...]
    >> Two:
    >> C++ way: prohibit definition of types in there parameter list of a
    >> function declaration.

    >
    > I'm not a C++ lawyer (nor even a C++ fluent speaker (although I
    > have "C++ Readability," go figure)), but "no type declarations in
    > function declarations" seems awfully restrictive:
    >
    > int main(int argc, char **argv) // BZZZZT!
    >
    > What must one do instead?
    >
    > typedef char **charStarStar;
    > int main(int argc, charStarStar argv)
    >
    > ? But, as I say, I don't speak That Other Language, and maybe I've
    > read more into your synopsis than was actually present.


    I think the restriction in C++ is that you can't define a new type name
    (either a typedef name or a tag) in a prototype or as a return type.
    "char**" is, in some sense, an existing type, not a new one.

    I haven't found the rule in the C++ standard that states this
    explicitly, but the annex that describes incompatibilities between C and
    C++ mentions it.

    For example, this:

    void f( struct S { int a; } arg ) {}

    is valid in C, but invalid in C++. (I'd say it's poor style in C.)

    [...]

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jun 24, 2012
    #14
  15. Eric Sosman

    Alan Curry Guest

    In article <>,
    Keith Thompson <> wrote:
    > (Alan Curry) writes:
    >
    >> Anyway, putting type names and variable names into a single category and
    >> calling them "identifiers" is a false generalization. It works at the
    >> technical level for the compiler implementor I guess, but besides that what's
    >> the reason for lumping them together and insisting that they behave the same?
    >> If you can't explain it without the word "identifier" then there is no
    >> reason, it's just a thought process that's being misled by a bit of escaped
    >> compiler-writer's jargon.

    >
    >I'd say it's a perfectly valid generalization. They *are* both
    >identifiers, and they follow the same scope rules.


    They "are" both identifiers because the word "identifier" has been defined
    that way. This is a circular argument. It doesn't prove that they belong
    together in a class, just that they have been forced into one and an awkward
    name has been slapped on it.

    >
    >You advocate treating type names as a special case with different scope
    >rules than other identifiers. That's a valid preference, but not one
    >that I share -- and not one that's consistent with C as it's currently
    >defined.


    More like no scope rules at all. Just a global table of types. (Global within
    a single run of the compiler). Any time a new struct tag is seen, just add it
    to the table and leave it there until the compiler exits. A type has an
    existence inherently outside of any function because types are more
    fundamental than functions.

    >>
    >> The same could be said for a function that's only called by one other
    >> function. Should we have nested functions then?

    >
    >Many languages do have nested functions. What tends to make them
    >complicated is the need to define rules for accessing objects defined
    >in an outer function. I wouldn't strongly object to adding nested
    >functions to C (and gcc supports them as an extension), but I don't
    >think they're all that important; we've gotten along without them
    >for a very long time.


    That complication (closures) is a good reason to want nested functions. It
    can be emulated without help from the compiler, but not easily. What's the
    corresponding reason for wanting struct definitions inside a function?

    >
    >[...]
    >
    >> Variable scopes make sense because the object named by the variable doesn't
    >> exist until the function is called. A type isn't an object.

    >
    >Are you conflating scope and lifetime?
    >


    Are you seriously saying they aren't (or shouldn't be) closely tied together?

    --
    Alan Curry
     
    Alan Curry, Jun 24, 2012
    #15
  16. Eric Sosman

    Alan Curry Guest

    In article <js5rl3$5pf$>,
    Eric Sosman <> wrote:
    >On 6/23/2012 8:56 PM, Alan Curry wrote:
    >> In article <js5l0m$64l$>,

    >
    >> Anyway, putting type names and variable names into a single category and
    >> calling them "identifiers" is a false generalization.

    >
    > If type names are somehow segregated from names-of-other-things,
    >does that mean
    >
    > double int = 42;
    > long * double void(short long);
    > struct struct { long *union; char enum; };
    >
    >... are to your liking?


    That would depend on whether it adds any conflicts to the grammar. If not, go
    for it. We already allow this:

    struct foo { int i; };
    struct bar { short x,y; };
    typedef struct bar bar;
    static struct foo foo(bar foo, bar bar) { }

    although it doesn't look very good. But this:

    int stat(const char *, struct stat *);

    has been a respectable function for a long time.

    >
    > (In my early youth I was weaned on a language that had no
    >reserved words at all, a language in which `DO 10 I = (1 , 10)'
    >was perfectly legal and *not* a loop construct. For a while I
    >esteemed this as a sort of Purity. I got over it.)


    I had the opposite of that experience, CBM BASIC. You can't have a variable
    name that contains a keyword as a substring, because keywords are recognized
    regardless of the lack of spacing around them. Luckily there are only 2
    significant characters in a variable name so you'd never have a problem
    unless you flamboyantly extended your variable names with insignificant
    characters.

    >
    > But, hey: Back to the beginning. You asked whether a compiler
    >that obeyed 6.2.1p4 did so quote "for a real reason" end quote.
    >The answer to your question is "Yes," because 6.2.1p4 dictates
    >how the compiler must behave. Debate about whether 6.2.1p4 ought
    >to have said something else should be between you and X3J11, not
    >between you and me.


    Standards aren't reasons at all. Official rationale is supplied for a few
    things, the rest is just a record of decisions made and the reasons are found
    elsewhere in history.

    --
    Alan Curry
     
    Alan Curry, Jun 24, 2012
    #16
  17. Eric Sosman

    Jens Gustedt Guest

    Am 24.06.2012 07:40, schrieb Alan Curry:
    >> Are you conflating scope and lifetime?

    >
    > Are you seriously saying they aren't (or shouldn't be) closely tied together?


    Hm, your question is vague, I don't see the point you want to make.

    Lifetime is a property of objects that is determined at run time.
    Objects, in particular those that are allocated through malloc and
    friends, don't have a sensible notion of scope.

    Scope is a property of identifiers that only makes sense at
    compilation time. Identifiers don't have lifetime at all.

    Jens
     
    Jens Gustedt, Jun 24, 2012
    #17
  18. Eric Sosman

    Jens Gustedt Guest

    Am 24.06.2012 02:57, schrieb James Kuyper:
    > On 06/23/2012 07:54 PM, Eric Sosman wrote:
    >> A consequence of "What happens in prototype stays in prototype"
    >> is that *all* in-prototype identifiers' scopes are limited to the
    >> prototype itself. Yes, it leads to a useless construct -- but have
    >> you got a usable alternative?

    >
    > Two:
    > C++ way: prohibit definition of types in there parameter list of a
    > function declaration.
    >
    > Useful alternative: give types defined in a function's parameter list
    > the same scope as the function's declaration, rather than function
    > prototype scope.


    I don't think that this alternative would buy us much and would add up
    to confusion. Remember that struct can only be declared once, so the
    definition of such a function then must look (syntactically) different
    from the prototype since it can't redeclare the struct.

    There can only be some marginal code base that uses struct definitions
    in prototypes directly. They are basically useless. So the C++
    treatment would be a possible addition to C.

    Jens
     
    Jens Gustedt, Jun 24, 2012
    #18
  19. Eric Sosman

    James Kuyper Guest

    On 06/24/2012 04:56 AM, Jens Gustedt wrote:
    > Am 24.06.2012 02:57, schrieb James Kuyper:
    >> On 06/23/2012 07:54 PM, Eric Sosman wrote:
    >>> A consequence of "What happens in prototype stays in prototype"
    >>> is that *all* in-prototype identifiers' scopes are limited to the
    >>> prototype itself. Yes, it leads to a useless construct -- but have
    >>> you got a usable alternative?

    >>
    >> Two:
    >> C++ way: prohibit definition of types in there parameter list of a
    >> function declaration.
    >>
    >> Useful alternative: give types defined in a function's parameter list
    >> the same scope as the function's declaration, rather than function
    >> prototype scope.

    >
    > I don't think that this alternative would buy us much and would add up
    > to confusion. Remember that struct can only be declared once, so the
    > definition of such a function then must look (syntactically) different
    > from the prototype since it can't redeclare the struct.


    Yes, that is a valid point.

    > There can only be some marginal code base that uses struct definitions
    > in prototypes directly. They are basically useless. So the C++
    > treatment would be a possible addition to C.


    I've no objection to adopting the C++ approach, just pointing out that
    there are workable alternatives. The current rules allow a declaration
    that is useless for some rather subtle reasons, and I don't think that's
    a good idea.
    --
    James Kuyper
     
    James Kuyper, Jun 24, 2012
    #19
  20. Eric Sosman

    Tim Rentsch Guest

    (Alan Curry) writes:

    > In article <js2buv$evv$>,
    > Eric Sosman <> wrote:
    >>On 6/22/2012 1:30 PM, Kenneth Brody wrote:
    >>>
    >>> int foo(struct bar *);
    >>>
    >>> ...
    >>>
    >>> int foo(struct bar *baz)
    >>> {
    >>> ...
    >>> }
    >>>
    >>> The compiler decided that the "struct bar" in one place was not the same
    >>> "struct bar" in the other place.

    > [...]
    >>
    >> The compiler was right. The relevant text is in 6.2.1p4:

    >
    > But is the compiler right for a real reason, or is it just a continuation of
    > a historical accident?


    Surely not a historical accident, because prototypes didn't exist
    in C before it was standardized.

    > Why would you ever want this behavior?
    >
    > I don't even see why you'd ever want any scope for a struct type other than
    > "from here to the end of the file". Types are global things.


    To me it would be extremely counterintuitive for a type declared
    in a function prototype to "leak out" into the surrounding scope.

    Also, the behavior in C probably was chosen to match the behavior
    in C++, from whence prototypes were derived. So this is really
    a C++ question rather than a C question (1/2 :).
     
    Tim Rentsch, Jun 24, 2012
    #20
    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. Chris Fogelklou
    Replies:
    36
    Views:
    1,438
    Chris Fogelklou
    Apr 20, 2004
  2. oo@@oo
    Replies:
    1
    Views:
    302
    Hallvard B Furuseth
    Aug 4, 2006
  3. James Brown

    scope of struct definitions

    James Brown, Nov 3, 2006, in forum: C Programming
    Replies:
    2
    Views:
    289
  4. George
    Replies:
    1
    Views:
    336
    Victor Bazarov
    Nov 8, 2007
  5. Curt Sampson

    Scope in Method Definitions

    Curt Sampson, Apr 13, 2005, in forum: Ruby
    Replies:
    4
    Views:
    104
    Robert Klemme
    Apr 13, 2005
Loading...

Share This Page