Search code examples
cprototypescopedesignerspecifications

C Prototype scope


I learnt that

the type specifier that declares the identifier in 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.

Please see the C program mentioned below.

void fn (struct st {int a;} a, struct st b) ;

struct st obj ;

Compilers promptly issues an error as 'obj' size is unknown (or) struct st is not a 'type'. That's right! the declaration of the structure 'struct st' ends at the prototype declaration.

I believe prototype had this limit because we can use some variable names in the prototype declarations too. These names may conflict with the variables in the same scope (as that of function prototype). Like below.

void fn (int a) ;
int a ;

So, to allow the above declarations the scope of prototype is limited. (Correct me if I am wrong)

But, for a prototype declaration, parameter variable name are of no use. So, why is it being 'narrowly scoped'? What is the significance of having the parameter variable name? What is the language designer's (or) specification's thought on this?


Solution

  • The parameter names can help document the use of the parameters.

    Consider a memory setting function:

    void mem_set(void *, int, int);
    
    void mem_set(void *buffer, int value, int nbytes);
    

    Which is easier to understand?


    The structure type declaration as written is local to the function prototype. As you probably know (now, if not before), you need to define the type outside the scope of the prototype in order to use it successfully. That is, you must write:

    struct st {int a;};
    void fn(struct st a, struct st b);
    

    You say:

    I believe prototype had this limit because we can use some variable names in the prototype declarations too. These names may conflict with the variables in the same scope (as that of function prototype). Like below.

    void fn(int a);
    int a;
    

    So, to allow the above declarations the scope of prototype is limited. (Correct me if I am wrong)

    There's a possibility that GCC with '-Wshadow' would warn about the parameter 'a' shadowing the global variable 'a' - it would certainly do so in the function definition, and might do so in the function declaration. But that is not a mandatory warning; the code as written is legal C - albeit slightly dubious because of the shadowing.


    There is a protracted discussion in the comments about "why does C restrict (prevent) you from declaring a type in a parameter list", with the sub-text "because C++ does allow you to do it":

    Comments

    Being allowed of /**/, it should be the programmer's responsibility (as per coding practices) to add proper comments about the use of the language there. I believe there has to be 'something' other than providing assistance to comments. – Ganesh Gopalasubramanian

    OK - believe away. Compatibility with what C++ did was the rest of the reason, and the argument names were added there to promote readability. See Stroustrup 'Design and Evolution of C++'. Note that the names of the parameters in the prototype are not part of the interface - see the discussion on providing arguments by name instead of position. – Jonathan Leffler

    I believe the question the OP is asking is "what's the point of having function prototype scope at all?". You answer, unfortunately, does not shed any light on it. Frankly, I have no idea either. If they simply wanted to limit the scope of named parameter declarations (in a non-defining declaration) as OP guesses, they could've done it without introducing a scope (as it is done in C++ for example). – AndreyT

    @AndreyT: in a function definition, the arguments are local to the body of the function (it is no longer possible to hide an argument by a local variable in the outermost block of the body of the function). The prototype logically declares a type inside the function, and therefore should be scoped as defined - and hence, a type defined only in the function prototype cannot be used outside the function, and a function that cannot be called is of little benefit to anyone. – Jonathan Leffler

    @Jonathan Leffler: You seem to be explaining why the parameter names were allowed ("compatibility with C++" - OK). What I'd like to know is the rationale for introducing the "function prototype scope". Why did they see the need to introduce such a scope? C++ doesn't do it that way. There's no function prototype scope in C++. – AndreyT

    @AndreyT Yeh! We both are drowning in the same boat :) – Ganesh Gopalasubramanian

    Counter-example

    This demonstrates that C++ "does do it that way".

    #include <cstdio>
    using namespace std;
    
    extern void x(struct c {int y;} b);
    
    void x(struct c b)
    {
        printf("b.y = %d\n", b.y);
    }
    
    int main()
    {
        struct c a;
        a.y = 0;
        x(a);
        return(0);
    }
    

    This code does not compile with G++ (4.0.1 on MacOS X 10.5.8). It complains:

    $ g++ -o xx xx.cpp
    xx.cpp:4: error: types may not be defined in parameter types
    $
    

    The error occurs at default levels of warning/error - as well as at pedantic levels.

    So it seems fair and accurate to say "C behaves as C++ does" in this context. Can you demonstrate with a counter-counter-example how you can define a type in a function prototype in C++, specifying which C++ compiler and platform allows it?