cfunctionstructscopedeclaration

Structures declared in function prototypes


I have two functions. pos(), which defines a struct as its return type, and bar(), which defines a struct as an argument type:

#include <stdio.h>
#include <stdlib.h>

static struct foo { int x; } pos(void)
{
    return (struct foo) {10};
}

static int bar(struct point { int x, y; } pt) 
{
    return pt.x + pt.y;
}

int main(void)
{
    struct foo a = pos();
    printf("a.x: %d.\n", a.x);
#if 0
    int sum = bar((struct point){10, 20});
    printf("sum: %d.\n", sum);
#endif
    return EXIT_SUCCESS;
}

About which David R. Tribble here Incompatibilities Between ISO C and ISO C++ says that the scope of the structure declared in either of these fashions does not extend outside the function declaration or definition, making it impossible to define objects of that structure type which could be passed as arguments to the function or to assign function return values into objects of that type, and offers [C99: §6.2.1, 6.7.2.3, 6.7.5.3, I] as references.

But the former (struct foo) compiles and works perfectly fine (i.e. I am able to define objects of that structure type in main() can assign the function return value into an object of that type). GCC 13.1 and Clang 18.1 don't even raise any warning.

The latter (struct point) on the other hand, fails to compile. Why does the first one work, and the second one not? What are some possible use cases for these "fashions"?


Solution

  • For starters the function prototype and the function prototype scope are two different notions.

    The function prototype (the C Standard 6.2.1 Scopes of identifiers):

    1. ...A function prototype is a declaration of a function that declares the types of its parameters.

    Such a function declaration can be at the same time a function definition.

    As for the function prototype scope then

    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

    That is the quote refers to function prototypes that are not at the same time their definitions.

    Pay attention to that in your program example you do not have a function prototype scope.

    The structure struct foo is declared in the file scope.

    static struct foo { int x; } pos(void)
    {
        return (struct foo) {10};
    }
    

    So it is visible from its point of declaration.

    As for the structure struct point then it is declared in the block scope of the function bar

    static int bar(struct point { int x, y; } pt) 
    {
        return pt.x + pt.y;
    }
    

    So it is invisible outside the function.

    From the C Standard (6.2.1 Scopes of identifiers)

    If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit.

    and

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