below is my code:
//main.c
//I'm not using header file here,I know it is bad practice, it is just for demo purpose.
int main()
{
func();
return 0;
}
//test.c
void func()
{
...
}
we can see that above code compiles and can be linked by linker, but the same thing doesn't apply to variables as:
//main.c
int main()
{
sum += 1;
return 0;
}
//test.c
int sum = 2020;
then this code won't compile and can't be linked, and we have to add extern int sum; before main function in main.c.
But why we don't need to add extern in main.c as:
//main.c
extern void func(); //or `void func();` since functions are by default external
// without above line, it still compile
int main()
{
func();
return 0;
}
is it a little bit inconsistent here?
Note: by saying " Functions are by default external.",my understanding is: we can save some keystokes without typing extern , so void func(); == extern void func();, but we still need to add void func(); before main function in main.c, isn't it?
Both programs are incorrect since C99 and may be rejected by the compiler. An identifier may not be used in an expression without previously being declared.
In C89 there was a rule that if you write something that resembles a function call, and the function name has not previously been declared, then the compiler inserts a function declaration int f(); . There was not a similar rule for use of other identifiers that aren't followed by parentheses.
Some compilers (depending on compiler flags) will, even if set to C99 or later mode, issue a diagnostic and then perform the C89 behaviour anyway.
Note: your program still causes undefined behaviour in C89 because the implicit declaration is int func(); but the function definition has void func() which is incompatible type.
The compiler doesn't need to know anything about a function, in order to generate code to call it. In the absence of a prototype, it might generate the wrong code, but it can generate something (in principle, at least -- standards-compliance might forbid it by default). The compiler knows the calling convention for the platform -- it knows to put the function arguments onto the stack or into registers as required. It knows to write a symbol that the linker can later find and fix up, and so on.
But when you write "sum++", the compiler has no clue, lacking a declaration, how to generate code for that. It doesn't even know what kind of thing "sum" is. The code needed to increment a floating-point number will be completely different to that needed to increment an integer, and may be different from that needed to increment a pointer. The compiler doesn't need to know where "sum" is -- that's the linker's job -- but it needs to know what it is, to produce meaningful machine code.
But we don't need to add extern for the function in main.c as extern void func(); or void func();(as functions are implicitly extern prefixed) and the code still compile?
That's correct. Functions are by default external.
To make functions specific to a local source file (translation unit), you need to specific static for them.
Variables, on the other hand, are visible in the source file only. If you want to make some variable visible outside the source file where it is defined, you need extern for it.
There are two completely different topics - function prototypes and linkage.
void foo(void);
provides the extern function prototype needed by compiler to know the number and type of parameters and the type of the return value. Function has an external linkage - ie can be accessed by other compilation units
static void foo(void);
provides the static function prototype. Function has an no external linkage - ie it cannot be accessed by other compilation units
By default functions have an external linkage.
Objects (global scope).
int x;
Defines the object x having the external linkage and type int.
If you define another x object in another compilation unit the linker will complain and emit an error.
extern int x;
Only declares the object x without defining it. The object x has to be defined in other compilation unit.
Related
If we declare an object or function without defining it, how are we allowed to use it before its declaration and how are we not allowed to use it before its declaration ? (For a similar question using a forwarded declared structure tag before its definition, basically how we are allowed to use an incomplete type and how not, see https://stackoverflow.com/a/45725061/3284469)
Does it matter if the declaration appears in file scope or block scope?
Does it matter if its definition appears in the same or a different translation unit?
For example
extern int i;
(what can we do with i here?)
(what can't we do with i here?)
int A = i+3; // error: initializer element is not constant. This is an error not due to forward declaration of int i
int i = 3;
void fun();
(what can we do with fun here?)
(what can't we do with fun here?)
void fun(){};
Declaring an object is a promise to provide a definition at some other place. Once you declare a function or an external variable, from that point on you are allowed to do anything that you would be allowed to do to a function or a variable that you have defined.
The scope of the declaration has no effect on what you can do, only on the location in code where you can do it.
In most cases, code translator requires all external references to be satisfied at the time the code is linked. Otherwise, you get a linking error.
One exception to this rule is using declared object in a sizeof expression, which does not require an access to underlying object:
extern int undefined;
size_t res = sizeof(undefined);
The above will not break a link, because sizeof expression does not generate access to its arguments.
You can do anything with the declaration except for inlining it. For example:
void fun();
inline void fun(){}
After the declaration you can call the function, unless the definition is marked inline in which case it will result in a linker error because the definition does not emit a symbol to link against. Even if you don't say inline explicitly, an optimizing compiler may inline calls to the function if the definition has been seen.
www.cprogramming.com say's:
When you declare a variable, a function, or even a class all you are
doing is saying: there is something with this name, and it has this
type. The compiler can then handle most (but not all) uses of that
name without needing the full definition of that name. Declaring a
value--without defining it--allows you to write code that the compiler
can understand without having to put all of the details. This is
particularly useful if you are working with multiple source files, and
you need to use a function in multiple files. You don't want to put
the body of the function in multiple files, but you do need to provide
a declaration for it.
extern int i;
Here, an integer type variable i has been declared (but no definition i.e. no memory allocation for variable i so far). And we can do this declaration as many times as needed.
void fun();
Function fun() declare, but not defined. but it does tell the compiler that it can use this function and expect that it will be defined somewhere.
what can we do with i here
With
extern int i;
i can be declared as many times as required in the program.
You can have an initializer
extern int i = 0;
what can't we do with i here?
You can't use i without defining it in the program.
extern int i;
int main(void)
{
i = 10; // Will through an error
return 0;
}
In case of function this keyword only tells that the linkage for the function is extern. By default linkage of a function declaration/definition is extern.
I have this weird thing:
in a file1.c there's
extern void foo(int x, int y);
..
..
int tmp = foo(1,2);
in the project I could find only this foo():
in file2.c :
int foo(int x, int y, int z)
{
....
}
in file2.h :
int foo(int x, int y, int z);
file2.h isn't included in file1.c (this is why who wrote it used extern, i guess).
this project compiles fine, I think that's because in file1.c foo() will be looked for only during linkage, am I right?
but my real question is : why is the linkage succssful ?
after all, there is no such function as foo with 2 parameters....
and i'm in c .. so there's no overloading..
so what's going on ?
Because there is no overloading, the C compiler does not decorate the function names. The linker finds in file2.c a reference to function foo and in file1.c it finds a function foo. It cannot know their parameter lists do not match and happily use them.
Of course, when the function foo runs the value of z is garbage and the behavior of the program becomes unpredictable from that point on.
Calling a function with the wrong number (or types) of arguments is an error.
The standard requires the implementation to detect some, but not all of them.
What the standard calls an implementation, is typically a compiler with a separate linker (and some other things), where a compiler translates single translation units (that is, a preprocessed source file) into object files, which later get linked together.
While the standard doesn't distinct between them, its authors of course wrote it with the typical setup in mind.
C11 (n1570) 6.5.2.2 "Function calls", p2:
If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.
This is in a "constraints" section, which means, the implementation (in this case, that's the compiler) must complain and may abort translation if a "shall" requirement is violated.
In your case, there was a prototype visible, so the arguments of the function call must match with the prototype.
Similar requirements apply for a function definition with a prototype declaration in scope; if your function definition doesn't match the prototype, your compiler must tell you. In other words, as long as you ensure that all calls to a function and that function's definition are in the scope of the same prototype, you are told if there is a mismatch. This can be ensured if the prototype is in a header file which is included by all files with calls to that function and by the file containing its definition. We use header files with prototypes exactly for that reason.
In the code shown, this checking is by-passed by providing a non-matching prototype and not including the header file2.h.
Ibid. p9:
If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined.
Undefined behaviour means, the compiler is free to assume it doesn't happen, and is not required to detect if it does.
And in fact, on my machine, the generated object files from file2.c (I inserted a return 0; to have some function body), don't differ if I remove one of the function arguments, which means, the object file doesn't contain any information about the arguments und thus a compiler seeing only file2.o and file1.c hasn't got any chance to detect the violation.
You've mentioned overloading, so let's compile file2.c (with two and three arguments) as C++ and look at the object files:
$ g++ file2_three_args.cpp -c
$ g++ file2_two_args.cpp -c
$ nm file2_three_args.o
00000000 T _Z3fooiii
$ nm file2_two_args.o
00000000 T _Z3fooii
Function foo has its arguments incorporated into the symbol created for it (a process called name mangling), the object file indeed carries some information about the function types. Accordingly, we get an error at link time:
$ cat file1.cpp
extern void foo(int x, int y);
int main(void) {
foo(1,2);
}
$ g++ file2_three_args.o file1.cpp
In function `main':
file1.cpp:(.text+0x19): undefined reference to `foo(int, int)'
collect2: error: ld returned 1 exit status
This behaviour would also be allowed for a C implementation, aborting translation is a valid manifestation of undefined behaviour at compile or link time.
The way overloading in C++ is usually done actually allows such checks at link time. That C doesn't have built-in support for function overloading, and that the behaviour is undefined for the cases where the compiler cannot see the type mismatches, allows to generate symbols for functions without any type information.
First of all
extern void foo(int x, int y);
means exactly the same thing as
void foo(int x, int y);
The former is just an overly explicit way to write the same thing. extern fills no other purpose here. It is like writing auto int x; instead of int x, it means the very same thing.
In your case, the "foo" module (which you call file2) contains the function prototype as well as the definition. This is proper program design in C. What file1.c should be doing is to #include the foo.h.
For reasons unknown, whoever wrote file1.c didn't do this. Instead they are just saying "elsewhere in the project, there is this function, do not care about its definition, that's handled elsewhere".
This is bad programming practice. file1.c shouldn't concern itself with how things are defined elsewhere: this is spaghetti programming which creates a needless tight coupling between the caller and the module. There is also the chance that the actual function doesn't match the local prototype, in which case you would hopefully get linker errors. But there are no guarantees.
The code must be fixed like this:
file1.c
#include "foo.h"
...
int tmp = foo(1,2);
foo.h
#ifndef FOO_H
#define FOO_H
int foo(int x, int y, int z);
#endif
foo.c
#include "foo.h"
int foo(int x, int y, int z)
{
....
}
In a particular C project, a file say file1.c uses a function say FUNCTION2(). The FUNCTION2() is declared in file2.c. An extern declaration of FUNCTION2() is there in file1.h
The file1.c adds only file1.h.
In file1.h, the file2.c/file2.h is not added. Still the compilation is successful and the functionality is working.
In the compilation list of the project, file2.c/file2.h is compiled first. But is that possible to call functions without adding the header file?
You can, but I wouldn't advise it. You have arranged things to force the compiler to exploit implicit declaration:
int main()
{
foo(2); /* The compiler emits this by implicit declaration. */
return 0;
}
int foo(int x)
{
return x;
}
In your explicit case, extern is telling the compiler to expect foo to come from a different compilation unit.
The standard thing to do would be to put a prototype of foo in a header and include that.
I have the following source code which interests me.
#include <stdio.h>
extern int foo;
int foo = 32;
int main()
{
printf("%d", foo);
}
This a perfectly normal piece of code, and when I compile it with
gcc -Wall -Wextra -pedantic foo.c
I get no warnings.
And it seems weird, because a variable is defined both as external, and also global in the same file.
I'm quite sure that it's easy to the linker to find the reference for the external variable in the same file, but doesn't it look like a coding error? And if so, why doesn't the compiler warn about this?
There's nothing weird. You first made a declaration of a variable (you promised the compiler that it exist) and then you actually defined it. There's no problem in that.
Also, by default, all variables that aren't local to functions and aren't defined as static are extern.
You seem to misunderstand what extern does. extern simply makes your declaration just a declaration instead of a definition.
int i; //definition of i
extern int i; //declaration of i
It is perfectly normal to have multiple declarations of the same variable, but only one definition should be present in the whole program. Compare this with a function
void f(void); //declaration
void f(void) //definition(and redeclaration)
{
} //definition
In order to use a variable or function, you only need its declaration. Its definition may appear anywhere in the program (the linker will find it). Anywhere can be the same file, another file, or even an external library.
And it's seems weired, because a variable is defined both as external, and also global in the same file.
extern int foo;
says: it declares without defining an object of type int named foo.
int foo = 32;
it declares and defines an object of type int named foo with external linkage.
There is no contradiction and it is valid C code.
The difference is that the former is a declaration -> extern declares a variable and says it will be available somewhere around. You can have as many declarations as you want and the latter is a definition which must be there exactly once.
So there should be no warning and no error.
extern is a way to provide visibility to a variable that is defined elsewhere...
extern is like a promise...
in example.h
extern int g;// promises that this will be in the object code to anything that includes example.h
example. c
int g;
Does the order in which C objects appear on the file matter?
For example, in functions, if I create two functions and the one above references the other one will it work? (Yes it will, I've tried it.)
Is the same in effect for static functions, INLINE functions, etc.?
Is the same in effect for structs? What happens if I reference a struct which is defined further down on the .c file?
Is this to any extend compiler-specific? How does the compiler work in this case? Does it first scan the whole file for all declarations/definitions and then attempts to dereference functions/symbols?
First, if by "if I create two functions and the one above references the other one will it work?" you mean something like this:
int foo()
{
return bar();
}
int bar()
{
return 0;
}
Then the compiler may do educated guesses at what bar() is, but it will at least spit a warning if bar() wasn't already declared. For symbols that can't be called (like variables or types), it's an outright error if they're used before they're declared.
In C, whenever you use an identifier (and no matter the kind of the identifier: it may be a function, a variable, a type, etc.), it should be declared beforehand. The various modifiers you may add to any identifier (like you said, static, inline and all the others) have no impact on this.
Do not confuse declaration and definition. A declaration is just telling the compiler that a name exists; a definition actually tells the compiler what it is.
For instance, this is a definition:
int bar() { return 4; }
Notice how it has a body, with (simple) code inside.
This is the matching declaration:
int bar();
The compiler will gladly accept the use of a function as soon as it sees either the declaration or the definition for it. For organization reasons and better flexibility, it's often better to write declarations for all your functions at the top of your C file (or inside an included header file) then the definitions.
So, my first example should look like this:
int foo();
int bar();
int foo()
{
return bar();
}
int bar()
{
return 0;
}
With the declarations above the C code, I can change the order of the functions in any way I like.
Typically something must be defined above where you use it. You can avoid this in different ways for different situations.
For functions, just provide a prototype above where it's called and all will be well.
int trol(int a, int b);
// use trol(int, int)
int trol(int a, int b) { }
If you have two functions, a and b, and they call each other and are defined in the order of: a, b, then you must provide b's prototype above the definition of a. a's prototype is not required because it is defined above where it is used inside b. Then the compiler will have no problems.
One other special case for functions is that you can use a function without declaring it and the compiler will try to infer the signature from the call. This answer explains it pretty well I think: Must declare function prototype in C?
For structs, you can use pointers to them before they are actually defined (but you can't access any of the fields) by providing a forward declaration:
struct s;
// use s*'s
struct s { };
(The above scenario facilitates recursive data structures like linked lists and trees; you can use pointers to structs before they are fully defined because the size of any type of pointer is constant.)
It matters, because if the compiler doesn't know what the function is - it will try to 'guess' (create a default int foo() prototype with matching parameters), and if your call is incorrect - you'll have mismatches (build errors, implicit castings, whatever).
It is common practice (if not even required) to declare the function before calling it (through prototypes aka forward declarations).
For functions with variable parameter lists (like printf) you must have a forward declaration for them to work properly. For example this code will not compile:
int foo(int a)
{
b(a);
b("hello", "kitty");
}
void b(int a, ...)
{
printf("%d", a);
}
But this - will:
#include <stdio.h>
int foo(int a)
{
return b(a);
}
int b(int a)
{
return printf("%d", a);
}
(with warning about the implicit forward declaration)
So in order to avoid dealing with the order of the objects in the file - use prototyping (forward declarations) to let the compiler know what's following.
From my experience, everything in C has to be written with the referenced "object" before the reference is made. I don't think this is specific to any compiler, but maybe there are some which I haven't found. Basically, everything always has to be:
Object Declaration
...
Object Reference