use of out-of-scope declaration - c

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'?

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

Related

Why does the compiler not recognize the function void message()?

I am actually working C language on Ubuntu 18.04. I don't use any IDE.
#include <stdio.h>
void main()
{
message();
printf("\nCry, and you stop the monotomy!\n");
}
void message()
{
printf("\nSmile, and the worldsmiles with you...");
}
When I run this it returns error message as follows.
msg.c: In function ‘main’:
msg.c:5:2: warning: implicit declaration of function ‘message’ [-Wimplicit-function-declaration]
message();
^~~~~~~
msg.c: At top level:
msg.c:8:6: warning: conflicting types for ‘message’
void message()
^~~~~~~
msg.c:5:2: note: previous implicit declaration of ‘message’ was here
message();
^~~~~~~
When I put the message function above main() then it shows no error. Why is it? Can't we put functions after main()? What is implicit declaration here?
You can put functions after main if you want; just if you're calling them in main, before they're defined, you should also declare them before main:
void message();
void main()
...
Without this the compiler assumes that message is an externally linked function returning int, and then when it comes across your actual definition of message it complains about conflicting types for message (since it already decided that message returns int, not void).
You first to define or declare your method, before calling it. In the following example, I declare the method before calling it in main:
#include<stdio.h>
// Declare the method
void message();
void main()
{
// Call the method
message();
printf("\nCry, and you stop the monotomy!\n");
}
// Define the method
void message()
{
printf("\nSmile, and the worldsmiles with you...");
}
PS: I would change the return type of main() to an int. Read more in What should main() return in C and C++?
When the compiler gets to message(); (in main) the compiler knows nothing about the function message.
It now tries its best. So it gives you are warning and then assumes that message should have been declared int message();
So when the compiler finally gets to void message() - it says "hello - I thought it would be int messgae". Hence the warning.
Simply put either message before main, so when it gets to compiling main the compiler knows about message.
Or as other posters have said. Declare it at the top.
When i put the message function above main() then it shows no error. Why is it? Can't we put functions after main()?
C source files are parsed top-down. So by the time compiler sees the function call message (in main), it must know about it (the same applies to any symbol, basically). That's why putting it above works but below results in diagnostics.
At a minimum, you must provide a declaration for any identifier before their use.
What is implicit declaration here?
When the compiler sees a function call and didn't know about it, it assumes the function returns an int (Such as int message();). This is the "implicit declaration". This was an ancient rule that was valid until C99.
But in C99 and later, this rule has been removed. Thus your code (that puts the definition of "message" below main without a declaration) is invalid in C99 and later.
See C function calls: Understanding the "implicit int" rule.
Later when the compiler sees the actual definition of message (i.e., void message() {...), it sees the return type is actually void. Thus this conflicts with its own declaration (where it assumed its int). So it generates:
msg.c:8:6: warning: conflicting types for ‘message’

Rationale of static declaration followed by non-static declaration allowed but not vice versa

This code will compile and is well defined under current C standards:
static int foo(int);
extern int foo(int);
The standard specifies that in this situation (C11: 6.2.2 Linkages of identifiers (p4)):
For an identifier declared with the storage-class specifier extern in
a scope in which a prior declaration of that identifier is visible,31)
if the prior declaration specifies internal or external linkage, the
linkage of the identifier at the later declaration is the same as the
linkage specified at the prior declaration. [...]
... which means that the int foo(int) function is declared static int foo(int).
Swapping these declarations around like this:
extern int foo(int);
static int foo(int);
...gives me a compiler error using GNU GCC:
static declaration of 'foo' follows non-static declaration
My question is: What is the design rationale behind the second case being an error and not handled in a similar way as the first case? I suspect it has something to do with the fact that separate translation units are easier to manage and #include? I feel as though without understanding this, I can open myself up to some mistakes in future C projects.
I think the idea of this confusing specification is that an extern declaration can be used inside a function to refer to a global function or object, e.g to disambiguate it from another identifier with the same name
static double a; // a declaration and definition
void func(void) {
unsigned a;
.....
if (something) {
extern double a; // refers to the file scope object
}
}
Whereas if you use static you declare something new:
extern double a; // just a declaration, not a definition
// may reside elsewhere
void func(void) {
unsigned a;
.....
if (something) {
static double a; // declares and defines a new object
}
}
I can imagine that the scenario leading to this asymmetry is that the default linkage of identifiers at global scope is extern.1 Failing to mark the definition of a previously static-declared function static as well would otherwise be an error because it is by default also an extern declaration.
Here is an illustration. In modern C, functions must be declared before use, but sometimes the implementation is at the end because it is secondary to the main purpose of the code in the file:
static void helper_func(); // typically not in a header
// code using helper_func()
// And eventually its definition, which by default
// declares an **external** function. Adding
// an explicit `extern` would not change a thing; it's redundant.
void helper_func() { /* ... */ }
This looks innocent enough, and the intent is clear. When C was standardized there was probably code around looking like this. That's why it is allowed.
Now consider the opposite:
extern void func(); // this could be in a header
// ... intervening code, perhaps a different file ...
static void func() { /* ... */ }
// code which uses func()
It's pretty clear that this should not be allowed. Defining a function static is a clear, explicit statement. A prior, contradicting extern declaration does not make sense.2 There is a good chance that this is an inadvertent name collision, for example with a function declared in a header. Probably not much code out there was looking like this at the time of formalization. That's why it is forbidden.
1 From the C17 draft, 6.2.2/5: "If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern."
2 One could argue that an explicit extern declaration using the keyword, followed by a static definition, should be forbidden while an implicit one, without the keyword, could still be allowed (and that, correspondingly, a later explicitly extern function definition after a static declaration should be forbidden, while implicit ones are still allowed). But there is a limit to the hair-splitting a standard should do (and it's gone pretty far already).

Correct way to define a prototype

Came across a situation where I was in doubt how to define the prototype the correct way. It´s easier to just look at a simple example:
Document A.c:
#define foo bar
void mon() {
foo();
}
Document B.c:
void bar() {
Do something;
}
Gives following warning:
Warning: Function does not have a full prototype
Normally I would solve it by:
extern void foo(void);
But as example show, the function dont exactly exist but is defined to point on another function. What is the correct way to make a prototype for this?
If the compiler encounters the declaration extern void foo(void); after the #define foo bar for the same source file, it will parse it as extern void bar(void); And the linker will just solve the bar symbol.
Note that you definition of bar is not consistent with the declaration above. The definition of bar should read:
void bar(void) {
// Do something;
}
in C, unlike C++, an argument list of (void) is subtly different from an empty argument list.
I think, that what happens is the following:
The compiler replaces the macro foo with bar but since at that stage bar is not declared anywhere as a function the compiler will complain, that it cannot find it.
Please see more: Are prototypes required for all functions in C89, C90 or C99?

Can we call functions before defining it?

#include <stdio.h>
void main()
{
m();
}
void m()
{
printf("hi");
}
Output
hi
Warnings
main.c:11:10: warning: conflicting types for 'm' [enabled by default]
void m()
^
main.c:7:9: note: previous implicit declaration of 'm' was here
m();
^
Why this program runs successfully even though m() is called before it is defined?
And what is the meaning of the warning?
C89 allow this by implicitly converting the return type of function and parameter passed to it to int. See here.
But, this is not valid in C99 and later. This has been omitted from the standard. Either you have to declare a prototype for your function or define it before main. See the result here. There is a compile time error in this case.
If you don't declare a function in K&RC/C89, it's implicitly declared as returning int. Since yours returns void there's a mismatch.
If you add a prototype:
void m(void);
...before it's called, it'll fix things.
No, but you can declare it:
#include <stdio.h>
// declare m()
void m();
void main()
{
// use m()
m();
}
// define m()
void m()
{
printf("hi");
}
function declaration needs to be add before the first call of the function.
A full declaration includes the return type and the number and type of the arguments. This is also called the function prototype.
So you are Missing function prototype.
Add function declaration as void m(); to the code.
Edit:
C program allow to use forward declaration
.
In your case void m(); represents forward declaration of a function and is the function's prototype. After processing this declaration, the compiler would allow the user to refer to the entity m in the rest of the program.
Definition for a function must be provided somewhere (same file or other, where it would be responsibility of the linker to correctly match references to particular function in one or several object files with its definition, which must be unique, in another): (From wikipedia page)
That is why defining function after main work in your program.
Yes - It is called using prototypes.
I.e. put
void m();
At the start of the file
No, you cant normally.
The code would print the error something like this if the function is not defined before invoking it:
s.c: In function 'main':
s.c:4:1: warning: implicit declaration of function 'm' [-Wimplicit-function-declaration]
4 | m();
| ^
s.c: At top level:
s.c:8:6: warning: conflicting types for 'm'
8 | void m(){
| ^
s.c:4:1: note: previous implicit declaration of 'm' was here
4 | m();
| ^
So, it is always a good practice to declare method before or inside of main method especially if you are defining a method outside the scope of main function.
The code snippet for best practice has been provided below:
#include <stdio.h>
void m();
void main()
{
m();
}
void m()
{
printf("hi");
}

Two function declarations with void and empty argument list

I'd like to know why the following code:
void foo(void);
void foo()
{
}
is valid in gcc. In C, there is no such thing as overloading and above declarations (in fact, one of them is a definition) declare two different functions (the first one doesn't take any arguments, the second one could take any number of arguments of any types).
However, if we provide a definition for the first function:
void foo(void)
{
}
void foo()
{
}
a compilation fails this time due to redefinition. But still, the first code is correct and might be confusing as in the following:
void foo(void);
int main(void)
{
foo(); //OK
//foo(5); //Wrong, despite ->the definition<- allows it
}
void foo()
{
}
On the other hand, something like this is invalid straightaway:
void foo(int);
void foo() //error: number of arguments doesn't match prototype
{
}
I think the compiler's behavior is kinda weird in comparison to my first foregoing code. int isn't equal to (/*empty list*/) and neither is void.
Can anyone explain this ?
Quoting a late draft of the standard about function declarators:
(6.7.6.3/10) The special case of an unnamed parameter of type void as the
only item in the list specifies that the function has no parameters.
(6.7.6.3/14) An identifier list declares only the identifiers of the
parameters of the function. An empty list in a function declarator
that is part of a definition of that function specifies that the
function has no parameters.
So the declarators of the declaration and definition are in fact compatible, and thus refer to the same function (with no overloading taking place of course, as such a thing does not exist in C.)
The line below is a function declaration, which tells the signature of the function foo: what is the type of the returned value and what are the types of the arguments.
void foo(void);
Below there is a function definition, which tells what does the function do. It does not overload anything. The definition and the declaration must match in the signature. void data type allows omitting it in the function definition.
void foo()
{
}
Since void is not an instantiable type (you cannot have a value of type void) it is OK to omit the arguments in the signature of the function's definition. However, if you try to do:
void foo(void*);
void foo() {
}
then you'll have a compile error because foo is expected to get a pointer to a don't-worry-about-type value.
C Standard defines for void as:-
The void type comprises an empty set of values; it is an incomplete
type that cannot be completed.
And the definition
void foo()
{
}
implies that the parameters are empty set of values which is valid for definition,so the gcc allows.
Also prototype for function declaration specifies:-
The special case of an unnamed parameter of type void as the only item
in the list specifies that the function has no parameters.

Resources