Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

use of out-of-scope declaration

Tags:

c

gcc

clang

Code:

void foo() {
    extern int a;
    extern void b(int);
}

void bar() {
    b(9); // ok, warning: use of out-of-scope declaration of 'b'
    a=9; // error: use of undeclared identifier 'a'
}

Why the compiler doesn't just give a warning like use of out-of-scope declaration of 'a'?

like image 274
noinput Avatar asked Aug 15 '18 01:08

noinput


1 Answers

This is because of the vestigial feature of implicit declaration of functions. If you had just

void bar()
{
    b(9);    
}

that would actually be 100% valid pre-standard C (well, except that void didn't exist back then, but that's not important right now) equivalent to writing

void bar()
{
    extern int b();
    b(9);    
}

(Remember that an empty parameter list in a function declaration does not mean that the function takes zero arguments. It means the function takes an unspecified number of arguments.)

Now, when you have

void foo()
{
    extern void b(int);
}

void bar()
{
    b(9);
}

the implicit declaration means it's like you wrote

void foo()
{
    extern void b(int);
}

void bar()
{
    extern int b();
    b(9);
}

The two declarations of the external symbol b are not compatible. If they were both visible in the scope of bar, this would be a constraint violation ("X is a constraint violation" is the closest the C standard ever comes to saying "a program that does X is invalid and the compiler must reject it"). But they're not, so instead, the program's meaning is undefined. clang seems to have decided to apply the declaration from the foo scope but also warn you about it, which seems fair to me. gcc does treat it as an error:

test.c:6:5: error: incompatible implicit declaration of function ‘b’
     b(9);
     ^
test.c:2:17: note: previous implicit declaration of ‘b’ was here
     extern void b(int);
                 ^

("previous implicit declaration" is not quite right, but that is also not important right now.)

You can probably see how this sort of thing could lead to hard-to-find bugs, which is why modern best practice is to declare stuff with external linkage only at file scope, and to declare all functions with full prototypes.

Only functions are ever implicitly declared, which is why a gave a hard error; in your original example, a is completely invisible to bar. (Note that if you had redeclared it with a different type, that would also make the program's meaning undefined.)

like image 105
zwol Avatar answered Oct 20 '22 15:10

zwol